Client - refacto + display fix and improvements

This commit is contained in:
Sam 2021-10-02 16:16:58 +02:00
parent 3d56eb3c93
commit 60a5df70a9
38 changed files with 140 additions and 127 deletions

View File

@ -1,20 +1,13 @@
<template>
<div id="about">
<img class="bike-img" v-bind:src="bike_image_url" alt="mountain bike" />
<img class="bike-img" :src="'/img/bike.svg'" alt="mountain bike" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
<script>
export default {
name: 'About',
setup() {
return {
bike_image_url: './img/bike.svg',
}
},
})
}
</script>
<style scoped lang="scss">

View File

@ -15,9 +15,7 @@
},
setup() {
const { t } = useI18n()
return {
t,
}
return { t }
},
})
</script>

View File

@ -16,7 +16,7 @@
props: {
withoutTitle: {
type: Boolean,
default: true,
default: false,
},
},
})

View File

@ -1,6 +1,6 @@
<template>
<div class="dropdown-wrapper">
<div class="dropdown-selected" @click="openDropdown">
<div class="dropdown-selected" @click="toggleDropdown">
<slot></slot>
</div>
<ul class="dropdown-list" v-if="isOpen">
@ -41,25 +41,19 @@
let isOpen = ref(false)
let dropdownOptions = props.options.map((option) => option)
function openDropdown() {
isOpen.value = true
function toggleDropdown() {
isOpen.value = !isOpen.value
}
function updateSelected(option: IDropdownOption) {
emit('selected', option)
isOpen.value = false
}
function getSelectedLabel(selectedValue: string) {
return props.options.filter(
(option: IDropdownOption) => option.value === selectedValue
)[0].label
}
return {
dropdownOptions,
updateSelected,
getSelectedLabel,
isOpen,
openDropdown,
toggleDropdown,
updateSelected,
}
},
})

View File

@ -1,5 +1,5 @@
<template>
<div id="error404">
<div id="error">
<div class="error-content">
<h1>{{ title }}</h1>
<p>{{ message }}</p>
@ -37,7 +37,7 @@
<style scoped lang="scss">
@import '~@/scss/base';
#error404 {
#error {
display: flex;
align-items: center;
justify-content: center;

View File

@ -1,8 +1,8 @@
<template>
<div class="error-message">
<ul v-if="Array.isArray(message)">
<li v-for="(submessage, index) in message" :key="index">
{{ t(submessage) }}
<li v-for="(subMessage, index) in message" :key="index">
{{ t(subMessage) }}
</li>
</ul>
<div v-else>{{ t(message) }}</div>
@ -20,9 +20,7 @@
},
setup() {
const { t } = useI18n()
return {
t,
}
return { t }
},
})
</script>

View File

@ -1,7 +1,7 @@
<template>
<div id="modal">
<div class="custom-modal">
<Card :without-title="false">
<Card>
<template #title>
{{ title }}
</template>
@ -79,6 +79,15 @@
margin: 25% auto;
z-index: 1250;
@media screen and (max-width: $medium-limit) {
margin: 15% auto;
width: 100%;
}
@media screen and (max-width: $small-limit) {
margin: 50% 0;
width: 100%;
}
::v-deep(.card) {
border: 0;
margin: 0;
@ -102,12 +111,5 @@
}
}
}
@media screen and (max-width: $small-limit) {
.custom-modal {
margin: 50% 0;
width: 100%;
}
}
}
</style>

View File

@ -13,7 +13,7 @@
import Error from '@/components/Common/Error.vue'
export default defineComponent({
name: 'NotFoundView',
name: 'NotFound',
components: {
Error,
},

View File

@ -17,12 +17,12 @@
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'
import CyclingSport from '@/components/Common/Sports/CyclingSport.vue'
import CyclingTransport from '@/components/Common/Sports/CyclingTransport.vue'
import Hiking from '@/components/Common/Sports/Hiking.vue'
import MountainBiking from '@/components/Common/Sports/MountainBiking.vue'
import Running from '@/components/Common/Sports/Running.vue'
import Walking from '@/components/Common/Sports/Walking.vue'
import CyclingSport from '@/components/Common/SportImage/CyclingSport.vue'
import CyclingTransport from '@/components/Common/SportImage/CyclingTransport.vue'
import Hiking from '@/components/Common/SportImage/Hiking.vue'
import MountainBiking from '@/components/Common/SportImage/MountainBiking.vue'
import Running from '@/components/Common/SportImage/Running.vue'
import Walking from '@/components/Common/SportImage/Walking.vue'
import { sportColors } from '@/utils/sports'
export default defineComponent({

View File

@ -10,7 +10,7 @@
<span class="map-attribution-text">©</span>
<a
class="map-attribution-text"
href="http://www.openstreetmap.org/copyright"
href="https://www.openstreetmap.org/copyright"
target="_blank"
rel="noopener noreferrer"
>

View File

@ -35,11 +35,11 @@
},
setup(props) {
const { t } = useI18n()
// eslint-disable-next-line
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getNumber(value: any): number {
return isNaN(value) ? 0 : +value
}
// eslint-disable-next-line
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getSum(total: any, value: any): number {
return getNumber(total) + getNumber(value)
}

View File

@ -1,6 +1,6 @@
<template>
<div class="timeline-workout">
<Card>
<Card :without-title="true">
<template #content>
<div class="workout-user-date">
<div class="workout-user">
@ -83,7 +83,7 @@
import { useI18n } from 'vue-i18n'
import Card from '@/components/Common/Card.vue'
import SportImage from '@/components/Common/Sports/SportImage.vue'
import SportImage from '@/components/Common/SportImage/index.vue'
import StaticMap from '@/components/Common/StaticMap.vue'
import { ROOT_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'

View File

@ -1,24 +1,33 @@
<template>
<div id="timeline">
<div class="section-title">{{ t('workouts.LATEST_WORKOUTS') }}</div>
<WorkoutCard
v-for="workout in workouts"
:workout="workout"
:sport="
workouts.length > 0
? sports.filter((s) => s.id === workout.sport_id)[0]
: null
"
:user="user"
:key="workout.id"
/>
<div v-if="workouts.length === 0" class="no-workouts">
{{ t('workouts.NO_WORKOUTS') }}
<div v-if="user.nb_workouts > 0 && workouts.length === 0">
<WorkoutCard
v-for="index in [...Array(initWorkoutsCount).keys()]"
:user="user"
:key="index"
/>
</div>
<div v-if="moreWorkoutsExist" class="more-workouts">
<button @click="loadMoreWorkouts">
{{ t('workouts.LOAD_MORE_WORKOUT') }}
</button>
<div v-else>
<WorkoutCard
v-for="workout in workouts"
:workout="workout"
:sport="
workouts.length > 0
? sports.filter((s) => s.id === workout.sport_id)[0]
: null
"
:user="user"
:key="workout.id"
/>
<div v-if="workouts.length === 0" class="no-workouts">
{{ t('workouts.NO_WORKOUTS') }}
</div>
<div v-if="moreWorkoutsExist" class="more-workouts">
<button @click="loadMoreWorkouts">
{{ t('workouts.LOAD_MORE_WORKOUT') }}
</button>
</div>
</div>
</div>
</template>
@ -56,12 +65,14 @@
required: true,
},
},
setup() {
setup(props) {
const store = useStore()
const { t } = useI18n()
let page = ref(1)
const per_page = 5
const initWorkoutsCount =
props.user.nb_workouts >= per_page ? per_page : props.user.nb_workouts
onBeforeMount(() => loadWorkouts())
const workouts: ComputedRef<IWorkout[]> = computed(
@ -85,6 +96,7 @@
}
return {
initWorkoutsCount,
moreWorkoutsExist,
per_page,
workouts,

View File

@ -23,6 +23,7 @@
<script lang="ts">
import { format } from 'date-fns'
import { defineComponent } from 'vue'
export default defineComponent({
name: 'CalendarHeader',
props: {

View File

@ -25,11 +25,11 @@
import { defineComponent, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import SportImage from '@/components/Common/Sports/SportImage.vue'
import SportImage from '@/components/Common/SportImage/index.vue'
import { IWorkout } from '@/types/workouts'
export default defineComponent({
name: 'CalendarWorkouts',
name: 'CalendarWorkout',
components: {
SportImage,
},

View File

@ -1,6 +1,6 @@
<template>
<div id="user-calendar">
<Card class="calendar-card">
<Card class="calendar-card" :without-title="true">
<template #content>
<CalendarHeader
:day="day"

View File

@ -1,6 +1,6 @@
<template>
<div class="user-month-stats">
<Card :without-title="false">
<Card>
<template #title>{{ $t('dashboard.THIS_MONTH') }}</template>
<template #content>
<div v-if="Object.keys(statistics).length === 0">

View File

@ -1,6 +1,6 @@
<template>
<div class="records-card">
<Card :without-title="false">
<Card>
<template #title>
<SportImage :sport-label="records.label" />
{{ sportTranslatedLabel }}
@ -31,7 +31,7 @@
import { useI18n } from 'vue-i18n'
import Card from '@/components/Common/Card.vue'
import SportImage from '@/components/Common/Sports/SportImage.vue'
import SportImage from '@/components/Common/SportImage/index.vue'
import { IRecord } from '@/types/workouts'
export default defineComponent({
@ -93,7 +93,7 @@
}
}
}
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
font-size: 1em;
.card-title {
font-size: 1em;

View File

@ -52,10 +52,7 @@
props.user.timezone
)
)
return {
recordsBySport,
t,
}
return { recordsBySport, t }
},
})
</script>

View File

@ -1,6 +1,6 @@
<template>
<div class="user-stat-card">
<Card>
<Card :without-title="true">
<template #content>
<div class="stat-content">
<div class="stat-icon">

View File

@ -7,6 +7,10 @@
disabled: registration_disabled,
}"
>
<AlertMessage
message="user.REGISTER_DISABLED"
v-if="registration_disabled"
/>
<form @submit.prevent="onSubmit(action)">
<div class="form-items">
<input
@ -48,10 +52,6 @@
</button>
</form>
<ErrorMessage :message="errorMessages" v-if="errorMessages" />
<AlertMessage
message="user.REGISTER_DISABLED"
v-if="registration_disabled"
/>
</div>
</div>
</div>
@ -133,9 +133,9 @@
buttonText,
errorMessages,
formData,
onSubmit,
registration_disabled,
router,
onSubmit,
}
},
})
@ -162,15 +162,16 @@
border-color: var(--disabled-color);
}
}
@media screen and (max-width: $medium-limit) {
margin-top: $default-margin;
width: 100%;
}
}
@media screen and (max-width: $medium-limit) {
height: auto;
margin-bottom: 50px;
#user-form {
margin-top: $default-margin;
width: 100%;
}
}
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div id="workout-chart">
<Card :without-title="false">
<Card>
<template #title>{{ t('workouts.ANALYSIS') }} </template>
<template #content>
<div class="chart-radio">

View File

@ -84,7 +84,7 @@
import { PropType, defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'
import SportImage from '@/components/Common/Sports/SportImage.vue'
import SportImage from '@/components/Common/SportImage/index.vue'
import { ISport } from '@/types/sports'
import { IWorkoutObject } from '@/types/workouts'

View File

@ -28,7 +28,11 @@
class="workout-data"
v-if="workoutObject.maxAlt !== null && workoutObject.minAlt !== null"
>
<img class="mountains" src="/img/workouts/mountains.svg" />
<img
class="mountains"
src="/img/workouts/mountains.svg"
:alt="t('workouts.ELEVATION')"
/>
{{ t('workouts.MIN_ALTITUDE') }}: <span>{{ workoutObject.minAlt }} m</span
><br />
{{ t('workouts.MAX_ALTITUDE') }}:

View File

@ -5,7 +5,7 @@
<div class="leaflet-container" v-if="workoutData.workout.with_gpx">
<LMap
v-if="geoJson.jsonData && center && bounds.length === 2"
:zoom="options.zoom"
:zoom="13"
:center="center"
:bounds="bounds"
ref="workoutMap"
@ -108,17 +108,18 @@
const appConfig: ComputedRef<IAppConfig> = computed(
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]
)
const center = computed(() => getCenter(bounds))
const geoJson = computed(() =>
props.workoutData && props.workoutData.gpx
? getGeoJson(props.workoutData.gpx)
: {}
)
return {
appConfig,
bounds: bounds,
center: computed(() => getCenter(bounds)),
geoJson: computed(() =>
props.workoutData && props.workoutData.gpx
? getGeoJson(props.workoutData.gpx)
: {}
),
options: { zoom: 13 },
bounds,
center,
geoJson,
t,
workoutMap,
fitBounds,

View File

@ -7,7 +7,7 @@
@confirmAction="deleteWorkout(workoutObject.workoutId)"
@cancelAction="updateDisplayModal(false)"
/>
<Card :without-title="false">
<Card>
<template #title>
<WorkoutCardTitle
:sport="sport"
@ -213,7 +213,7 @@
.card-content {
display: flex;
flex-direction: row;
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
flex-direction: column;
}
}

View File

@ -1,6 +1,9 @@
<template>
<div id="workout-edition">
<Card :without-title="false">
<div
id="workout-edition"
:class="{ 'center-form': workout && workout.with_gpx }"
>
<Card>
<template #title>{{
t(`workouts.${isCreation ? 'ADD' : 'EDIT'}_WORKOUT`)
}}</template>
@ -424,10 +427,15 @@
#workout-edition {
margin: 100px auto;
width: 700px;
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
width: 100%;
margin: 0 auto 50px auto;
}
@media screen and (max-width: $small-limit) {
&.center-form {
margin: 50px auto;
}
}
::v-deep(.card) {
.card-title {
@ -436,7 +444,7 @@
}
.card-content {
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
padding: $default-padding 0;
}
@ -454,7 +462,7 @@
flex-direction: row;
justify-content: space-between;
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
flex-direction: column;
}
}
@ -481,7 +489,7 @@
justify-content: space-around;
label {
font-weight: normal;
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
font-size: 0.9em;
}
}
@ -513,7 +521,7 @@
padding: $default-padding;
div {
display: flex;
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
flex-direction: column;
}
ul {

View File

@ -1,6 +1,6 @@
<template>
<div id="workout-note">
<Card :without-title="false">
<Card>
<template #title>{{ t('workouts.NOTES') }}</template>
<template #content>
{{ notes && notes !== '' ? notes : t('workouts.NO_NOTES') }}</template

View File

@ -1,6 +1,6 @@
<template>
<div id="workout-segments">
<Card :without-title="false">
<Card>
<template #title>{{ t('workouts.SEGMENT', 2) }}</template>
<template #content>
<ul>

View File

@ -1,7 +1,7 @@
<template>
<div id="dashboard" v-if="authUser.username && sports.length > 0">
<div class="container mobile-menu">
<Card>
<Card :without-title="true">
<template #content>
<button
class="mobile-menu-item"
@ -145,7 +145,7 @@
display: none;
}
@media screen and (max-width: $small-limit) {
@media screen and (max-width: $medium-limit) {
padding-bottom: 60px;
.dashboard-container {
display: flex;

View File

@ -66,7 +66,3 @@
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base';
</style>

View File

@ -36,28 +36,36 @@
@import '~@/scss/base';
#loginOrRegister {
display: flex;
height: 100%;
.container {
display: flex;
flex-direction: row;
justify-content: space-evenly;
height: 100%;
margin-bottom: $default-margin * 2;
width: 100%;
.container-sub {
min-width: 50%;
height: 100%;
}
@media screen and (max-width: $medium-limit) {
display: block;
}
@media screen and (max-width: $medium-limit) {
height: auto;
.container {
.container-sub {
align-items: center;
.bike-img {
margin-top: $default-margin * 1.5;
max-width: 60%;
}
}
}
}
@media screen and (max-width: $small-limit) {
.container {
flex-direction: column;
}
}
}
</style>