Skip to content

Commit

Permalink
feat(timers): Redesign timers and remove dependency on day.js (#186)
Browse files Browse the repository at this point in the history
* feat(timer): Redesign traditional timer

* feat(timer): Make traditional timer mobile-friendly

* feat(timer): Percentage timer calculates its value by itself

* feat(timer): Update approximate timer
Timer does not depend on DayJS anymore and its design was updated

* feat(timer): Timers emit their own page titles using `@tick`

* fix(timer): Adjust font sizes for mobile

* refactor: Remove day.js dependency

* refactor: Remove day.js specific commands from i18nwatcher

* refactor: Compact settingsTime time formatting

* refactor: Remove settingsTime dependency on day.js

* refactor(timer): Remove Source Sans Pro from percentage timer

* chore: Remove commented Source Sans Pro from Nuxt config

* chore: Remove unused Source Sans Pro SCSS
  • Loading branch information
Hanziness committed Feb 19, 2022
1 parent f786a0d commit cdd7093
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 131 deletions.
1 change: 0 additions & 1 deletion assets/scss/SourceSansPro_Numbers.scss

This file was deleted.

14 changes: 4 additions & 10 deletions components/settings/items/settingsTime.vue
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ export default {
}
const errorAdditionalInfo = {
min: this.$dayjs.formatMs(this.minMs, { format: 'mm:ss' }),
max: this.$dayjs.formatMs(this.maxMs, { format: 'mm:ss' })
min: this.msToTimeStr(this.minMs),
max: this.msToTimeStr(this.maxMs)
}
const valueInMs = this.timeStrToMs(newValue)
Expand Down Expand Up @@ -125,16 +125,10 @@ export default {
},
msToTimeStr (value) {
let seconds = Math.round(value / 1000) % 60
const seconds = (Math.round(value / 1000) % 60).toString().padStart(2, '0')
const minutes = '' + ((Math.round(value / 1000) - seconds) / 60)
if (seconds < 10) {
seconds = '0' + seconds
} else {
seconds = '' + seconds
}
return minutes + ':' + seconds
return `${minutes}:${seconds}`
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions components/timer/display/_timerSwitch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<div class="w-full h-full relative flex flex-col justify-center text-center text-black dark:text-gray-100 transition-opacity duration-500 select-none" :class="[{ 'opacity-70': !running, 'opacity-100': running }]">
<Transition name="timer-switch" mode="out-in">
<CompleteMarker v-if="$store.getters['schedule/getCurrentTimerState'] === 3" :key="'complete'" />
<TimerTraditional v-else-if="timerWidget === 'traditional'" :key="'traditional'" v-bind="timerInfo" />
<TimerApproximate v-else-if="timerWidget === 'approximate'" :key="'approximate'" v-bind="timerInfo" />
<TimerPercentage v-else-if="timerWidget === 'percentage'" :key="'percentage'" v-bind="timerInfo" />
<TimerTraditional v-else-if="timerWidget === 'traditional'" v-bind="timerInfo" :key="'traditional'" @tick="$emit('tick', $event)" />
<TimerApproximate v-else-if="timerWidget === 'approximate'" v-bind="timerInfo" :key="'approximate'" @tick="$emit('tick', $event)" />
<TimerPercentage v-else-if="timerWidget === 'percentage'" v-bind="timerInfo" :key="'percentage'" @tick="$emit('tick', $event)" />
</Transition>
</div>
</template>
Expand Down
45 changes: 33 additions & 12 deletions components/timer/display/timerApproximate.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
<template>
<div :class="['timer-display select-none text-3xl md:text-7xl xl:text-9xl', { 'active': running }]">
<div :class="['timer-display select-none flex flex-row gap-2 items-center leading-none', { 'active': running }]">
<transition name="transition-approximate-up" mode="out-in">
<div :key="value" class="timer-approximate">
{{ value }}
<div :key="time.value" :style="{ '--ch': Math.ceil(Math.log10(time.value + 1)) }" class="text-9xl xl:text-[12rem] font-bold text-right time-value">
{{ time.value }}
</div>
</transition>
<transition name="transition-approximate-up" mode="out-in">
<div :key="time.string" class="text-3xl xl:text-7xl">
{{ time.string }}
</div>
</transition>
</div>
Expand All @@ -14,29 +19,45 @@ import TimerMixin from '@/assets/mixins/timerMixin'
export default {
mixins: [TimerMixin],
computed: {
value () {
const lang = this.$store.state.settings.lang
return this.$dayjs.formatRelative(this.timeOriginal - this.timeElapsed, {
lang
})
time () {
const remainingMinutes = (this.timeOriginal - this.timeElapsed) / (1000 * 60)
const timeObject = {
value: 0,
string: null
}
if (remainingMinutes > 59) {
timeObject.value = Math.round(remainingMinutes / 60)
timeObject.string = this.$i18n.tc('timer.approximate.hours', timeObject.value)
} else {
timeObject.value = Math.ceil(remainingMinutes)
timeObject.string = this.$i18n.tc('timer.approximate.minutes', timeObject.value)
}
this.$emit('tick', `${timeObject.value} ${timeObject.string}`)
return timeObject
}
}
}
</script>

<style lang="scss" scoped>
div.timer-approximate.transition-approximate-up-enter-active,
div.timer-approximate.transition-approximate-up-leave-active {
div.time-value {
width: calc(var(--ch) * 1ch);
}
.transition-approximate-up-enter-active,
.transition-approximate-up-leave-active {
transition: 300ms ease-out;
transition-property: opacity, transform;
}
div.timer-approximate.transition-approximate-up-enter {
.transition-approximate-up-enter {
opacity: 0 !important;
transform: translateY(30px) !important;
}
div.timer-approximate.transition-approximate-up-leave-to {
.transition-approximate-up-leave-to {
opacity: 0 !important;
transform: translateY(-30px) !important;
}
Expand Down
26 changes: 14 additions & 12 deletions components/timer/display/timerPercentage.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<template>
<div class="timer-percentage select-none text-8xl md:text-[14rem] font-bold timer-display" :class="[{ 'active': running }]">
<div class="timer-percentage select-none timer-display flex flex-row items-center gap-4" :class="[{ 'active': running }]">
<transition name="transition-percentage" tag="span" mode="out-in">
<span :key="timerValue" class="relative inline-block" v-text="timerValue" />
<span
:key="timerValue"
:style="{ 'width': `${Math.max(1, Math.ceil(Math.log10(timerValue + 1)))}ch` }"
class="relative inline-block text-9xl md:text-[14rem] font-bold"
v-text="timerValue"
/>
</transition>
<span>%</span>
<span class="text-4xl md:text-8xl">%</span>
</div>
</template>

Expand All @@ -14,21 +19,18 @@ export default {
mixins: [TimerMixin],
computed: {
timerValue () {
return this.$dayjs.formatPercentage(this.timeOriginal - this.timeElapsed, {
total: this.timeOriginal,
addPercentage: false
})
const completeRounded = Math.round((this.timeOriginal - this.timeElapsed) / 1000)
const totalRounded = Math.round(this.timeOriginal / 1000)
const percentageValue = Math.round(((totalRounded - completeRounded) / totalRounded) * 100)
this.$emit('tick', `${percentageValue}%`)
return percentageValue
}
}
}
</script>

<style lang="scss" scoped>
@import '@/assets/scss/SourceSansPro_Numbers.scss';
div.timer-percentage {
font-family: 'Source Sans Pro', monospace;
}
.transition-percentage-enter-active,
.transition-percentage-leave-active {
transition: 300ms ease-out;
Expand Down
65 changes: 53 additions & 12 deletions components/timer/display/timerTraditional.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,63 @@
<template>
<div :class="['timer-traditional font-bold text-7xl lg:text-[14rem] timer-display', { 'active': running }]" v-text="$dayjs.formatMs(timeOriginal - timeElapsed, {})" />
<div
:class="['flex flex-row gap-0 md:text-[14rem] text-[9rem] leading-none timer-display relative', { 'active': running }]"
>
<transition-group
name="transition-traditional"
enter-class="translate-x-4 opacity-0"
enter-active-class="duration-500"
enter-to-class=""
leave-class=""
leave-active-class="duration-300 absolute"
leave-to-class="opacity-0"
move-class="duration-500"
class="flex flex-col items-center md:flex-row"
tag="div"
>
<div
v-for="key in timeLeftStructured.displayKeys"
:key="key"
class="transition flex flex-row"
:class="{ 'font-bold': key === 'minutes', 'md:text-9xl md:self-start': key === 'seconds', 'md:mr-4': key === 'hours' }"
tag="div"
>
<span
v-for="(char, idx) in timeLeftStructured.num[key].toString().padStart(2, '0')"
:key="`${key}-${idx}`"
class="w-[1ch]"
:class="{ 'md:text-right text-center': idx === 0, 'md:text-left text-center': idx === 1 }"
v-text="char"
/>
</div>
</transition-group>
</div>
</template>

<script>
import TimerMixin from '@/assets/mixins/timerMixin'
export default {
mixins: [TimerMixin]
}
</script>
mixins: [TimerMixin],
computed: {
timeLeftStructured () {
const sLeft = Math.round((this.timeOriginal - this.timeElapsed) / 1000)
const hours = Math.floor(sLeft / (60 * 60))
const minutes = Math.floor((sLeft % (60 * 60)) / (60))
const seconds = Math.floor(sLeft % 60)
<style lang="scss" scoped>
@import '@/assets/scss/SourceSansPro_Numbers.scss';
const returnObject = {
num: { hours, minutes, seconds },
displayKeys: ['hours', 'minutes', 'seconds'].filter(value => value !== 'hours' || hours > 0)
}
.timer-traditional {
font-family: 'Source Sans Pro', monospace;
font-variant-numeric: tabular-nums;
font-feature-settings: "lnum" on;
letter-spacing: 0.5rem;
this.$emit(
'tick',
returnObject.displayKeys
.map(key => returnObject.num[key].toString().padStart(2, '0'))
.join(':')
)
return returnObject
}
}
}
</style>
</script>
6 changes: 6 additions & 0 deletions i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ export default {
stop: 'Reset timer',
advance: 'Go to next section'
},
timer: {
approximate: {
hours: 'hour | hours',
minutes: 'minute | minutes'
}
},
settings: {
heading: 'Settings',
tabs: {
Expand Down
6 changes: 6 additions & 0 deletions i18n/hu.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ export default {
stop: 'Időzítő megállítása',
advance: 'Ugrás a következő szakaszra'
},
timer: {
approximate: {
hours: 'óra | óra',
minutes: 'perc | perc'
}
},
settings: {
heading: 'Beállítások',
tabs: {
Expand Down
2 changes: 0 additions & 2 deletions nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export default defineNuxtConfig({
** https://nuxtjs.org/guide/plugins
*/
plugins: [
'@/plugins/dayjs.js',
'@/plugins/i18nlanguages.js',
{ src: '@/plugins/notifications.client.js', ssr: false },
{ src: '@/plugins/vuex-persist.client.js', ssr: false },
Expand Down Expand Up @@ -180,7 +179,6 @@ export default defineNuxtConfig({
googleFonts: {
families: {
Poppins: [400, 700]
// 'Source Sans Pro': [700]
},
display: 'swap'
// download: true
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"@nuxtjs/i18n": "^7.0.3",
"@nuxtjs/pwa": "^3.3.5",
"@nuxtjs/sitemap": "^2.4.0",
"dayjs": "^1.8.32",
"nuxt-edge": "^2.16.0-27349935.777a4b7f",
"sass-loader": "^10.0.4",
"vue": "^2.6.14",
Expand Down
13 changes: 5 additions & 8 deletions pages/timer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
:timer-state="timerState"
:timer-widget="$store.state.settings.currentTimer"
class="grid absolute place-items-center"
@tick="timeString = $event"
/>
<TimerControls :class="['absolute', { 'pointer-events-none': preview }]" style="bottom: 2rem;" :can-use-keyboard="!preview && !showSettings" />
<TodoList v-show="$store.state.settings.tasks.enabled" class="absolute z-10" style="right: 24px; bottom: 24px;" :editing="[0].includes($store.state.schedule.timerState)" />
Expand Down Expand Up @@ -88,14 +89,15 @@ export default {
data () {
return {
showSettings: false
showSettings: false,
timeString: ''
}
},
head () {
if (this.preview) { return }
return {
title: `(${this.remainingTimeString}) ${this.pageTitle}`,
title: (this.remainingTimeString ? `(${this.remainingTimeString}) ` : '') + this.pageTitle,
meta: [{
hid: 'description',
name: 'description',
Expand Down Expand Up @@ -134,12 +136,7 @@ export default {
return this.$store.state.settings.pageTitle.useTickEmoji ? '' : this.$i18n.t('ready').toLowerCase()
}
const currentScheduleItem = this.$store.getters['schedule/getCurrentItem']
return this.$dayjs.getFormattedTime(
currentScheduleItem.length - currentScheduleItem.timeElapsed,
this.$store.state.settings.currentTimer,
{ total: currentScheduleItem.length, lang: this.$store.state.settings.lang }
)
return this.timeString
},
pageTitle () {
Expand Down
54 changes: 0 additions & 54 deletions plugins/dayjs.js

This file was deleted.

Loading

0 comments on commit cdd7093

Please sign in to comment.