Client - add workout details

This commit is contained in:
Sam
2021-09-24 19:51:04 +02:00
parent ea5be4037d
commit 0cf61a46de
22 changed files with 620 additions and 0 deletions

View File

@ -0,0 +1,98 @@
<template>
<div id="workout-info">
<div class="workout-data">
<i class="fa fa-clock-o" aria-hidden="true" />
{{ t('workouts.DURATION') }}: <span>{{ workout.moving }}</span>
<WorkoutRecord :workout="workout" record_type="LD" />
<div v-if="withPause">
({{ t('workouts.PAUSES') }}: <span>{{ workout.pauses }}</span> -
{{ t('workouts.TOTAL_DURATION') }}: <span>{{ workout.duration }})</span>
</div>
</div>
<div class="workout-data">
<i class="fa fa-road" aria-hidden="true" />
{{ t('workouts.DISTANCE') }}: <span>{{ workout.distance }} km</span>
<WorkoutRecord :workout="workout" record_type="FD" />
</div>
<div class="workout-data">
<i class="fa fa-tachometer" aria-hidden="true" />
{{ t('workouts.AVERAGE_SPEED') }}:
<span>{{ workout.ave_speed }} km/h</span
><WorkoutRecord :workout="workout" record_type="AS" /><br />
{{ t('workouts.MAX_SPEED') }}: <span>{{ workout.max_speed }} km/h</span>
<WorkoutRecord :workout="workout" record_type="MS" />
</div>
<div class="workout-data">
<img class="mountains" src="/img/misc/mountains.svg" />
{{ t('workouts.MIN_ALTITUDE') }}: <span>{{ workout.min_alt }} m</span
><br />
{{ t('workouts.MAX_ALTITUDE') }}: <span>{{ workout.max_alt }} m</span>
</div>
<div class="workout-data">
<i class="fa fa-location-arrow" aria-hidden="true" />
{{ t('workouts.ASCENT') }}: <span>{{ workout.ascent }} m</span><br />
{{ t('workouts.DESCENT') }}: <span>{{ workout.descent }} m</span>
</div>
<WorkoutWeather :workout="workout" />
</div>
</template>
<script lang="ts">
import { PropType, defineComponent, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import WorkoutRecord from '@/components/Workout/WorkoutDetail/WorkoutRecord.vue'
import WorkoutWeather from '@/components/Workout/WorkoutDetail/WorkoutWeather.vue'
import { IWorkout } from '@/types/workouts'
export default defineComponent({
name: 'WorkoutData',
components: {
WorkoutRecord,
WorkoutWeather,
},
props: {
workout: {
type: Object as PropType<IWorkout>,
required: true,
},
},
setup(props) {
const { t } = useI18n()
return {
withPause: computed(
() =>
props.workout.pauses !== '0:00:00' && props.workout.pauses !== null
),
t,
}
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base';
#workout-info {
display: flex;
flex-direction: column;
padding: $default-padding $default-padding * 2;
width: 100%;
.mountains {
margin-bottom: -3px;
height: 16px;
filter: var(--workout-img-color);
}
.workout-data {
text-transform: capitalize;
padding: $default-padding * 0.5 0;
span {
font-weight: bold;
text-transform: lowercase;
}
}
@media screen and (max-width: $small-limit) {
padding: $default-padding;
}
}
</style>

View File

@ -105,6 +105,7 @@
<style lang="scss" scoped>
@import '~@/scss/base';
#workout-map {
padding: $default-padding 0;
.leaflet-container {
height: 400px;
width: 600px;

View File

@ -0,0 +1,32 @@
<template>
<span
class="workout-record"
v-if="
workout.records &&
workout.records.find((record) => record.record_type === record_type)
"
>
<sup>
<i class="fa fa-trophy" aria-hidden="true" />
</sup>
</span>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { IWorkout } from '@/types/workouts'
export default defineComponent({
name: 'WorkoutRecord',
props: {
workout: {
type: Object as PropType<IWorkout>,
required: true,
},
record_type: {
type: String,
required: true,
},
},
})
</script>

View File

@ -0,0 +1,129 @@
<template>
<div id="workout-weather" v-if="workout.weather_start && workout.weather_end">
<table class="weather-table">
<thead>
<tr>
<th />
<th>
<div class="weather-th">
{{ t('workouts.START') }}
<img
class="weather-img"
:src="`/img/weather/${workout.weather_start.icon}.svg`"
:alt="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_start.icon}`)
"
:title="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_start.icon}`)
"
/>
</div>
</th>
<th>
<div class="weather-th">
{{ t('workouts.END') }}
<img
class="weather-img"
:src="`/img/weather/${workout.weather_end.icon}.svg`"
:alt="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_end.icon}`)
"
:title="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_end.icon}`)
"
/>
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<img
class="weather-img weather-img-small"
src="/img/weather/temperature.svg"
:alt="t(`workouts.WEATHER.TEMPERATURE`)"
:title="t(`workouts.WEATHER.TEMPERATURE`)"
/>
</td>
<td>{{ Number(workout.weather_start.temperature).toFixed(1) }}°C</td>
<td>{{ Number(workout.weather_end.temperature).toFixed(1) }}°C</td>
</tr>
<tr>
<td>
<img
class="weather-img weather-img-small"
src="/img/weather/pour-rain.svg"
:alt="t(`workouts.WEATHER.HUMIDITY`)"
:title="t(`workouts.WEATHER.HUMIDITY`)"
/>
</td>
<td>
{{ Number(workout.weather_start.humidity * 100).toFixed(1) }}%
</td>
<td>{{ Number(workout.weather_end.humidity * 100).toFixed(1) }}%</td>
</tr>
<tr>
<td>
<img
class="weather-img weather-img-small"
src="/img/weather/breeze.svg"
:alt="t(`workouts.WEATHER.WIND`)"
:title="t(`workouts.WEATHER.WIND`)"
/>
</td>
<td>{{ Number(workout.weather_start.wind).toFixed(1) }}m/s</td>
<td>{{ Number(workout.weather_end.wind).toFixed(1) }}m/s</td>
</tr>
</tbody>
</table>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import { IWorkout } from '@/types/workouts'
export default defineComponent({
name: 'WorkoutWeather',
props: {
workout: {
type: Object as PropType<IWorkout>,
required: true,
},
},
setup() {
const { t } = useI18n()
return { t }
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base';
#workout-weather {
padding-top: $default-padding;
.weather-img {
height: 30px;
filter: var(--workout-img-color);
}
.weather-img-small {
height: 20px;
}
.weather-table {
width: 100%;
text-align: center;
.weather-th {
display: flex;
flex-direction: column;
text-transform: capitalize;
}
tbody {
font-size: 0.8em;
}
}
}
</style>

View File

@ -54,6 +54,7 @@
</template>
<template #content>
<WorkoutMap :workout="workout" />
<WorkoutData :workout="workout.workout" />
</template>
</Card>
</div>
@ -65,6 +66,7 @@
import { useRoute } from 'vue-router'
import Card from '@/components/Common/Card.vue'
import WorkoutData from '@/components/Workout/WorkoutDetail/WorkoutData.vue'
import WorkoutMap from '@/components/Workout/WorkoutDetail/WorkoutMap.vue'
import { WORKOUTS_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'
@ -77,6 +79,7 @@
name: 'WorkoutDetail',
components: {
Card,
WorkoutData,
WorkoutMap,
},
props: {
@ -158,6 +161,13 @@
}
}
}
.card-content {
display: flex;
flex-direction: row;
@media screen and (max-width: $small-limit) {
flex-direction: column;
}
}
}
}
</style>