Merge branch 'master' of github.com:jcalixte/bons-programmeurs
This commit is contained in:
@@ -11,11 +11,12 @@
|
|||||||
"@vue/composition-api": "^1.0.0-beta.1",
|
"@vue/composition-api": "^1.0.0-beta.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"plyr": "^3.6.2",
|
"plyr": "^3.6.2",
|
||||||
"pretty-checkbox": "^3.0.3",
|
|
||||||
"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",
|
||||||
|
"vuex-composition-helpers": "^1.0.18",
|
||||||
|
"vuex-persist": "^2.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app" class="plume">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="120"
|
width="120"
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chilled-music">
|
<div class="chilled-music" v-show="false">
|
||||||
<div class="plyr__video-embed" id="player" v-show="false">
|
<div
|
||||||
<iframe src="https://www.youtube-nocookie.com/embed/5qap5aO4i9A"></iframe>
|
class="chilled-music plyr__video-embed"
|
||||||
</div>
|
id="player"
|
||||||
|
allowfullscreen
|
||||||
|
allowtransparency
|
||||||
|
allow="autoplay"
|
||||||
|
data-plyr-provider="youtube"
|
||||||
|
data-plyr-embed-id="5qap5aO4i9A"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -48,7 +54,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
chilledcow.video = new Plyr('#player')
|
chilledcow.video = new Plyr('#player', {
|
||||||
|
youtube: {
|
||||||
|
noCookie: true,
|
||||||
|
rel: 0,
|
||||||
|
showinfo: 0,
|
||||||
|
iv_load_policy: 3,
|
||||||
|
modestbranding: 1
|
||||||
|
},
|
||||||
|
quality: {
|
||||||
|
default: 240,
|
||||||
|
options: [240]
|
||||||
|
}
|
||||||
|
})
|
||||||
chilledcow.video.on('play', onPlay)
|
chilledcow.video.on('play', onPlay)
|
||||||
chilledcow.video.on('pause', onPause)
|
chilledcow.video.on('pause', onPause)
|
||||||
chilledcow.video.on('ready', () => {
|
chilledcow.video.on('ready', () => {
|
||||||
|
|||||||
@@ -8,30 +8,33 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed } from '@vue/composition-api'
|
import { defineComponent, computed } from '@vue/composition-api'
|
||||||
|
import { useInterval } from '../hooks/useInterval'
|
||||||
|
|
||||||
const MIN_INTERVAL = 1
|
const MIN_INTERVAL = 1
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'IntervalInput',
|
name: 'IntervalInput',
|
||||||
props: {
|
props: {
|
||||||
editable: { type: Boolean, required: true },
|
editable: { type: Boolean, required: true }
|
||||||
interval: { type: Number, required: true }
|
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup() {
|
||||||
|
const { interval, setInterval } = useInterval()
|
||||||
|
|
||||||
const minus = () => {
|
const minus = () => {
|
||||||
if (props.interval > MIN_INTERVAL) {
|
if (interval.value > MIN_INTERVAL) {
|
||||||
emit('update', props.interval - 1)
|
setInterval(interval.value - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const plus = () => {
|
const plus = () => {
|
||||||
emit('update', props.interval + 1)
|
setInterval(interval.value + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const label = computed(() =>
|
const label = computed(() =>
|
||||||
props.interval > MIN_INTERVAL ? 'minutes' : 'minute'
|
interval.value > MIN_INTERVAL ? 'minutes' : 'minute'
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
interval,
|
||||||
minus,
|
minus,
|
||||||
plus,
|
plus,
|
||||||
label
|
label
|
||||||
|
|||||||
68
src/components/ZoneMusic.vue
Normal file
68
src/components/ZoneMusic.vue
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<div class="zone-music">
|
||||||
|
<div class="pm-field">
|
||||||
|
<label for="use-music" data-pm-holder>
|
||||||
|
<span :class="{ disabled: withMusic }">Focus</span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="use-music"
|
||||||
|
id="use-music"
|
||||||
|
:checked="withMusic"
|
||||||
|
@change="setWithMusic(!withMusic)"
|
||||||
|
data-pm-checkbox-toggle
|
||||||
|
/>
|
||||||
|
<span :class="{ disabled: !withMusic }">Chill</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<ChilledMusic v-if="withMusic" :play="play" @play="play" @pause="pause" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from '@vue/composition-api'
|
||||||
|
import { useMusic } from '@/hooks/useMusic'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ZoneMusic',
|
||||||
|
components: {
|
||||||
|
ChilledMusic: () => import('@/components/ChilledMusic.vue')
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
play: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(_, { emit }) {
|
||||||
|
const { withMusic, setWithMusic } = useMusic()
|
||||||
|
|
||||||
|
const play = () => {
|
||||||
|
emit('play')
|
||||||
|
}
|
||||||
|
|
||||||
|
const pause = () => {
|
||||||
|
emit('pause')
|
||||||
|
}
|
||||||
|
|
||||||
|
return { withMusic, setWithMusic, play, pause }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/styles/variables';
|
||||||
|
|
||||||
|
label[data-pm-holder] {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: auto;
|
||||||
|
max-width: 300px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disabled {
|
||||||
|
color: darken($color, 60);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
13
src/hooks/useInterval.ts
Normal file
13
src/hooks/useInterval.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { useGetters, useActions } from 'vuex-composition-helpers'
|
||||||
|
import { GetterTree } from 'vuex'
|
||||||
|
import { State, RootActions } from '@/store'
|
||||||
|
|
||||||
|
export const useInterval = () => {
|
||||||
|
const { interval } = useGetters<GetterTree<State, State>>(['interval'])
|
||||||
|
const { setInterval } = useActions<RootActions>(['setInterval'])
|
||||||
|
|
||||||
|
return {
|
||||||
|
interval,
|
||||||
|
setInterval
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
import { ref } from '@vue/composition-api'
|
import { useGetters, useActions } from 'vuex-composition-helpers'
|
||||||
|
import { GetterTree } from 'vuex'
|
||||||
|
import { State, RootActions } from '@/store'
|
||||||
|
|
||||||
export const useMusic = () => {
|
export const useMusic = () => {
|
||||||
const hasMusic = ref(true)
|
const { withMusic } = useGetters<GetterTree<State, State>>(['withMusic'])
|
||||||
|
const { setWithMusic } = useActions<RootActions>(['setWithMusic'])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasMusic
|
withMusic,
|
||||||
|
setWithMusic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ref, computed, watch } from '@vue/composition-api'
|
import { ref, computed, watch } from '@vue/composition-api'
|
||||||
import { StopwatchState } from '@/types/StopwatchState'
|
import { StopwatchState } from '@/types/StopwatchState'
|
||||||
import { notify } from '@/utils/notification'
|
import { notify } from '@/utils/notification'
|
||||||
|
import { useInterval } from './useInterval'
|
||||||
|
|
||||||
const format = (num: number) => {
|
const format = (num: number) => {
|
||||||
return num.toString().padStart(2, '0')
|
return num.toString().padStart(2, '0')
|
||||||
@@ -16,9 +17,9 @@ const formatSeconds = (seconds: number) => {
|
|||||||
export const useTimer = () => {
|
export const useTimer = () => {
|
||||||
const timeState = ref<StopwatchState>('stopped')
|
const timeState = ref<StopwatchState>('stopped')
|
||||||
const seconds = ref(0)
|
const seconds = ref(0)
|
||||||
const interval = ref(5)
|
const { interval } = useInterval()
|
||||||
const sessionSeconds = ref(interval.value * 60)
|
const sessionSeconds = ref(interval.value * 60)
|
||||||
const isProgrammer1Turn = ref(true)
|
const isDev1Turn = ref(true)
|
||||||
|
|
||||||
const time = computed(() => formatSeconds(seconds.value))
|
const time = computed(() => formatSeconds(seconds.value))
|
||||||
const session = computed(() => formatSeconds(sessionSeconds.value))
|
const session = computed(() => formatSeconds(sessionSeconds.value))
|
||||||
@@ -36,14 +37,15 @@ export const useTimer = () => {
|
|||||||
|
|
||||||
stopwatchId = setInterval(() => {
|
stopwatchId = setInterval(() => {
|
||||||
seconds.value++
|
seconds.value++
|
||||||
if (seconds.value % intervalSeconds.value === 0) {
|
const isTimeToChange = seconds.value % intervalSeconds.value === 0
|
||||||
|
if (isTimeToChange) {
|
||||||
sessionSeconds.value = intervalSeconds.value
|
sessionSeconds.value = intervalSeconds.value
|
||||||
isProgrammer1Turn.value = !isProgrammer1Turn.value
|
isDev1Turn.value = !isDev1Turn.value
|
||||||
|
|
||||||
const dev = isProgrammer1Turn.value ? 'Dev 1' : 'Dev 2'
|
const dev = isDev1Turn.value ? 'Dev 1' : 'Dev 2'
|
||||||
|
|
||||||
notify('Changement !', {
|
notify('Change!', {
|
||||||
body: `${dev}, à votre tour !`
|
body: `${dev}, your turn!`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
@@ -69,7 +71,7 @@ export const useTimer = () => {
|
|||||||
pause()
|
pause()
|
||||||
seconds.value = 0
|
seconds.value = 0
|
||||||
sessionSeconds.value = intervalSeconds.value
|
sessionSeconds.value = intervalSeconds.value
|
||||||
isProgrammer1Turn.value = true
|
isDev1Turn.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -80,6 +82,6 @@ export const useTimer = () => {
|
|||||||
timeState,
|
timeState,
|
||||||
time,
|
time,
|
||||||
session,
|
session,
|
||||||
isProgrammer1Turn
|
isDev1Turn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ if (process.env.NODE_ENV === 'production') {
|
|||||||
setNotificationInstance((title, options?) =>
|
setNotificationInstance((title, options?) =>
|
||||||
sw.showNotification(title, options)
|
sw.showNotification(title, options)
|
||||||
)
|
)
|
||||||
notify('Une nouvelle version est disponible !', {
|
notify('An update is available!', {
|
||||||
body: `Fermer l'appli pour la mettre à jour.`
|
body: `Reload the app to install the update.`
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
offline() {
|
offline() {
|
||||||
|
|||||||
@@ -1,11 +1,55 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex, { ActionContext, ActionTree } from 'vuex'
|
||||||
|
import VuexPersistence from 'vuex-persist'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export interface State {
|
||||||
state: {},
|
interval: number
|
||||||
mutations: {},
|
withMusic: boolean
|
||||||
actions: {},
|
}
|
||||||
modules: {}
|
|
||||||
|
export interface RootActions extends ActionTree<State, State> {
|
||||||
|
setInterval: (ctx: ActionContext<State, State>, payload: number) => void
|
||||||
|
setWithMusic: (ctx: ActionContext<State, State>, payload: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const vuexLocal = new VuexPersistence<State>({
|
||||||
|
key: 'binome',
|
||||||
|
storage: window.localStorage
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const SET_INTERVAL = 'SET_INTERVAL'
|
||||||
|
const WITH_MUSIC = 'WITH_MUSIC'
|
||||||
|
|
||||||
|
const store = new Vuex.Store<State>({
|
||||||
|
state: {
|
||||||
|
interval: 5,
|
||||||
|
withMusic: true
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
interval: ({ interval }) => interval,
|
||||||
|
withMusic: ({ withMusic }) => withMusic
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
[SET_INTERVAL](state, interval: number) {
|
||||||
|
state.interval = interval
|
||||||
|
},
|
||||||
|
[WITH_MUSIC](state, withMusic: boolean) {
|
||||||
|
state.withMusic = withMusic
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setInterval({ commit }, interval: number) {
|
||||||
|
if (interval > 0) {
|
||||||
|
commit(SET_INTERVAL, interval)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setWithMusic({ commit }, withMusic: number) {
|
||||||
|
commit(WITH_MUSIC, withMusic)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [vuexLocal.plugin]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default store
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Fira+Mono&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Fira+Mono&display=swap');
|
||||||
@import '~pretty-checkbox/src/pretty-checkbox';
|
|
||||||
|
|
||||||
$color: #f8efba;
|
@import './variables';
|
||||||
$bgcolor: #2c3a47;
|
@import './plume';
|
||||||
$font-family: 'Fira Mono', monospace;
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
172
src/styles/plume.scss
Normal file
172
src/styles/plume.scss
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
:root {
|
||||||
|
--pm-placeholder-color: #999;
|
||||||
|
--pm-form-field-margin-bottom: 32px;
|
||||||
|
--pm-form-caption-font-size: 0.8em;
|
||||||
|
--pm-fieldset-border-style: solid;
|
||||||
|
--pm-fieldset-border-width: 1px;
|
||||||
|
--pm-fieldset-border-color: rgba(127, 127, 127, 0.4);
|
||||||
|
--pm-label-font-size: 1em;
|
||||||
|
--pm-label-font-weight: 600;
|
||||||
|
--pm-label-margin-bottom: 24px;
|
||||||
|
--pm-input-height: 40px;
|
||||||
|
--pm-input-box-shadow: none;
|
||||||
|
--pm-input-padding: 8px 16px;
|
||||||
|
--pm-input-border-style: solid;
|
||||||
|
--pm-input-border-radius: none;
|
||||||
|
--pm-input-border-width: 0 0 2px 0;
|
||||||
|
--pm-input-border-color: rgba(127, 127, 127, 0.4);
|
||||||
|
--pm-input-background-color: rgba(200, 200, 200, 0.1);
|
||||||
|
--pm-input-switch-size: 24px;
|
||||||
|
--pm-input-switch-border-width: 2px;
|
||||||
|
--pm-textarea-padding: 16px;
|
||||||
|
--pm-textarea-min-height: 100px;
|
||||||
|
}
|
||||||
|
.plume fieldset {
|
||||||
|
padding: 12px;
|
||||||
|
border-style: var(--pm-fieldset-border-style);
|
||||||
|
border-width: var(--pm-fieldset-border-width);
|
||||||
|
border-color: var(--pm-fieldset-border-color);
|
||||||
|
border-radius: var(--pm-input-border-radius);
|
||||||
|
}
|
||||||
|
.plume fieldset legend {
|
||||||
|
padding: 0 10px;
|
||||||
|
color: var(--pm-primary-color);
|
||||||
|
}
|
||||||
|
.plume .pm-field,
|
||||||
|
.plume fieldset {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: var(--pm-form-field-margin-bottom);
|
||||||
|
}
|
||||||
|
.plume label,
|
||||||
|
.plume legend {
|
||||||
|
display: block;
|
||||||
|
color: var(--pm-app-text-color);
|
||||||
|
font-weight: var(--pm-label-font-weight);
|
||||||
|
margin-bottom: var(--pm-label-margin-bottom);
|
||||||
|
}
|
||||||
|
.plume label[data-pm-holder],
|
||||||
|
.plume legend[data-pm-holder] {
|
||||||
|
font-weight: 300;
|
||||||
|
margin: 0 4px;
|
||||||
|
align-items: center;
|
||||||
|
display: inline-flex;
|
||||||
|
height: var(--pm-input-height);
|
||||||
|
}
|
||||||
|
.plume label.pm-required::after,
|
||||||
|
.plume legend.pm-required::after {
|
||||||
|
content: '*';
|
||||||
|
margin-left: 8px;
|
||||||
|
color: var(--pm-color-error);
|
||||||
|
}
|
||||||
|
.plume
|
||||||
|
input:not([type='range']):not([type='button']):not([type='reset']):not([type='submit']):not([type='checkbox']):not([type='radio']),
|
||||||
|
.plume textarea {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
.plume
|
||||||
|
input:not([type='range']):not([type='button']):not([type='reset']):not([type='submit']):not([type='checkbox']):not([type='radio']),
|
||||||
|
.plume select,
|
||||||
|
.plume textarea {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: var(--pm-input-height);
|
||||||
|
padding: var(--pm-input-padding);
|
||||||
|
box-shadow: var(--pm-input-box-shadow);
|
||||||
|
border-style: var(--pm-input-border-style);
|
||||||
|
border-color: var(--pm-input-border-color);
|
||||||
|
border-width: var(--pm-input-border-width);
|
||||||
|
border-radius: var(--pm-input-border-radius);
|
||||||
|
background-color: var(--pm-input-background-color);
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox'],
|
||||||
|
.plume input[type='radio'] {
|
||||||
|
margin: 0 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: var(--pm-input-switch-size);
|
||||||
|
height: var(--pm-input-switch-size);
|
||||||
|
border: solid var(--pm-input-switch-border-width);
|
||||||
|
border-color: var(--pm-input-border-color);
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox']::before {
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
content: '';
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
background-color: var(--pm-primary-color);
|
||||||
|
height: calc(100% - 4px);
|
||||||
|
width: calc(100% - 4px);
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox']:checked,
|
||||||
|
.plume input[type='radio']:checked {
|
||||||
|
border-color: var(--pm-primary-color);
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox']:checked::before,
|
||||||
|
.plume input[type='radio']:checked::before {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
.plume input[type='radio'],
|
||||||
|
.plume input[type='radio']:checked::before {
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox'][data-pm-checkbox-toggle] {
|
||||||
|
border-radius: 25px;
|
||||||
|
height: var(--pm-input-switch-size);
|
||||||
|
cursor: pointer;
|
||||||
|
width: calc(var(--pm-input-switch-size) * 2);
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox'][data-pm-checkbox-toggle]::before {
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
content: '';
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 100%;
|
||||||
|
height: calc(100% - 4px);
|
||||||
|
width: calc(
|
||||||
|
var(--pm-input-switch-size) - (var(--pm-input-switch-border-width) * 2) -
|
||||||
|
4px
|
||||||
|
);
|
||||||
|
background-color: var(--pm-input-border-color);
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox'][data-pm-checkbox-toggle]:checked {
|
||||||
|
border-color: var(--pm-input-border-color);
|
||||||
|
}
|
||||||
|
.plume input[type='checkbox'][data-pm-checkbox-toggle]:checked::before {
|
||||||
|
content: '';
|
||||||
|
top: 2px;
|
||||||
|
left: calc(var(--pm-input-switch-size) + 2px);
|
||||||
|
background-color: var(--pm-primary-color);
|
||||||
|
}
|
||||||
|
.plume:not(.pm-no-effects) input[type='checkbox']::after,
|
||||||
|
.plume:not(.pm-no-effects) input[type='checkbox']::before {
|
||||||
|
transition: 0.1s;
|
||||||
|
}
|
||||||
|
.plume:not(.pm-no-effects) [data-pm-success]:not([data-pm-success=''])::after {
|
||||||
|
-webkit-animation: slide-down 0.3s ease-out;
|
||||||
|
animation: slide-down 0.3s ease-out;
|
||||||
|
}
|
||||||
|
.plume:not(.pm-no-effects) [data-pm-error]:not([data-pm-error=''])::after {
|
||||||
|
-webkit-animation: slide-down 0.3s ease-out;
|
||||||
|
animation: slide-down 0.3s ease-out;
|
||||||
|
}
|
||||||
|
.plume:not(.pm-no-effects) [data-pm-warning]:not([data-pm-warning=''])::after {
|
||||||
|
-webkit-animation: slide-down 0.3s ease-out;
|
||||||
|
animation: slide-down 0.3s ease-out;
|
||||||
|
}
|
||||||
|
.plume:not(.pm-no-effects) [data-pm-info]:not([data-pm-info=''])::after {
|
||||||
|
-webkit-animation: slide-down 0.3s ease-out;
|
||||||
|
animation: slide-down 0.3s ease-out;
|
||||||
|
}
|
||||||
8
src/styles/variables.scss
Normal file
8
src/styles/variables.scss
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
$color: #f8efba;
|
||||||
|
$bgcolor: #2c3a47;
|
||||||
|
$font-family: 'Fira Mono', monospace;
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--pm-app-surface-color: #{#2c3a47};
|
||||||
|
--pm-primary-color: #{$color};
|
||||||
|
}
|
||||||
@@ -1,67 +1,40 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<IntervalInput
|
<IntervalInput :editable="timeState === 'stopped'" />
|
||||||
:interval="interval"
|
|
||||||
:editable="timeState === 'stopped'"
|
|
||||||
@update="(int) => (interval = int)"
|
|
||||||
/>
|
|
||||||
<section class="developers">
|
<section class="developers">
|
||||||
<DevSession
|
<DevSession position="1" :is-turn="isDev1Turn" :session="session" />
|
||||||
position="1"
|
<DevSession position="2" :is-turn="!isDev1Turn" :session="session" />
|
||||||
:is-turn="isProgrammer1Turn"
|
|
||||||
:session="session"
|
|
||||||
/>
|
|
||||||
<DevSession
|
|
||||||
position="2"
|
|
||||||
:is-turn="!isProgrammer1Turn"
|
|
||||||
:session="session"
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
<div class="global-time">{{ time }}</div>
|
<div class="global-time">{{ time }}</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button v-show="timeState === 'stopped'" @click="start">commencer</button>
|
<button v-show="timeState === 'stopped'" @click="start">start</button>
|
||||||
<button v-show="timeState === 'started'" @click="pause">pause</button>
|
<button v-show="timeState === 'started'" @click="pause">pause</button>
|
||||||
<button v-show="timeState === 'started'" @click="clear">arrêter</button>
|
<button v-show="timeState === 'started'" @click="clear">stop</button>
|
||||||
</div>
|
|
||||||
<div class="music">
|
|
||||||
<div class="pretty p-switch p-fill">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="use-music"
|
|
||||||
id="use-music"
|
|
||||||
v-model="hasMusic"
|
|
||||||
/>
|
|
||||||
<div class="state p-success">
|
|
||||||
<label for="use-music">son</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ChilledMusic
|
|
||||||
v-if="hasMusic"
|
|
||||||
:play="timeState === 'started'"
|
|
||||||
@play="start"
|
|
||||||
@pause="pause"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ZoneMusic
|
||||||
|
class="music"
|
||||||
|
:play="timeState === 'started'"
|
||||||
|
@play="start"
|
||||||
|
@pause="pause"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from '@vue/composition-api'
|
import { defineComponent } from '@vue/composition-api'
|
||||||
import { useTimer } from '@/hooks/useTimer'
|
import { useTimer } from '@/hooks/useTimer'
|
||||||
import { useMusic } from '@/hooks/useMusic'
|
|
||||||
import DevSession from '@/components/DevSession.vue'
|
import DevSession from '@/components/DevSession.vue'
|
||||||
import ChilledMusic from '@/components/ChilledMusic.vue'
|
import ZoneMusic from '@/components/ZoneMusic.vue'
|
||||||
import IntervalInput from '@/components/IntervalInput.vue'
|
import IntervalInput from '@/components/IntervalInput.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
components: {
|
components: {
|
||||||
DevSession,
|
DevSession,
|
||||||
ChilledMusic,
|
ZoneMusic,
|
||||||
IntervalInput
|
IntervalInput
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { hasMusic } = useMusic()
|
|
||||||
const {
|
const {
|
||||||
interval,
|
interval,
|
||||||
start,
|
start,
|
||||||
@@ -70,11 +43,10 @@ export default defineComponent({
|
|||||||
timeState,
|
timeState,
|
||||||
time,
|
time,
|
||||||
session,
|
session,
|
||||||
isProgrammer1Turn
|
isDev1Turn
|
||||||
} = useTimer()
|
} = useTimer()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasMusic,
|
|
||||||
interval,
|
interval,
|
||||||
start,
|
start,
|
||||||
pause,
|
pause,
|
||||||
@@ -82,7 +54,7 @@ export default defineComponent({
|
|||||||
timeState,
|
timeState,
|
||||||
time,
|
time,
|
||||||
session,
|
session,
|
||||||
isProgrammer1Turn
|
isDev1Turn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -109,4 +81,8 @@ button {
|
|||||||
.global-time {
|
.global-time {
|
||||||
font-size: calc(3em + 10vw);
|
font-size: calc(3em + 10vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.music {
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
23
yarn.lock
23
yarn.lock
@@ -5335,6 +5335,11 @@ lodash.memoize@^4.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||||
|
|
||||||
|
lodash.merge@^4.6.2:
|
||||||
|
version "4.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||||
|
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||||
|
|
||||||
lodash.template@^4.4.0:
|
lodash.template@^4.4.0:
|
||||||
version "4.5.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
|
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
|
||||||
@@ -6850,11 +6855,6 @@ pretty-bytes@^5.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
|
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
|
||||||
integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==
|
integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==
|
||||||
|
|
||||||
pretty-checkbox@^3.0.3:
|
|
||||||
version "3.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/pretty-checkbox/-/pretty-checkbox-3.0.3.tgz#d49c8013a8fc08ee0c2d6ebde453464bfdbc428e"
|
|
||||||
integrity sha1-1JyAE6j8CO4MLW695FNGS/28Qo4=
|
|
||||||
|
|
||||||
pretty-error@^2.0.2:
|
pretty-error@^2.0.2:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
|
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
|
||||||
@@ -8722,6 +8722,19 @@ vue@^2.6.11:
|
|||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
|
||||||
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
|
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
|
||||||
|
|
||||||
|
vuex-composition-helpers@^1.0.18:
|
||||||
|
version "1.0.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/vuex-composition-helpers/-/vuex-composition-helpers-1.0.18.tgz#62b50a6ec34885c113b825b18d9efbbe0ee28dfe"
|
||||||
|
integrity sha512-IM0CankybZn7rwm9EXQ13fG3w6c/zl89yOmrgI2CKd2dQIud53Hh73x48D++sV8ea9K530/vKyoAP5/drg1Ajg==
|
||||||
|
|
||||||
|
vuex-persist@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/vuex-persist/-/vuex-persist-2.2.0.tgz#4acec75562896b045c43d319690b93d6bc1b2bbc"
|
||||||
|
integrity sha512-o/qbBeMcKZZqMvCXc7kfIew/5cjHxlP1f53rx5YYp3r2tk2kxXYK/UZumxKn7OXywlurl2r0mgkuBzH6nIWFjw==
|
||||||
|
dependencies:
|
||||||
|
flatted "^2.0.0"
|
||||||
|
lodash.merge "^4.6.2"
|
||||||
|
|
||||||
vuex@^3.4.0:
|
vuex@^3.4.0:
|
||||||
version "3.5.1"
|
version "3.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.5.1.tgz#f1b8dcea649bc25254cf4f4358081dbf5da18b3d"
|
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.5.1.tgz#f1b8dcea649bc25254cf4f4358081dbf5da18b3d"
|
||||||
|
|||||||
Reference in New Issue
Block a user