diff --git a/assets/css/_bootstrap.scss b/assets/css/_bootstrap.scss index 33ecee15f88f2acd7c0753f866405354fbf21ffa..89d914e69bff99ce2e94aac8b7c37c95bd2bbfb2 100644 --- a/assets/css/_bootstrap.scss +++ b/assets/css/_bootstrap.scss @@ -42,7 +42,7 @@ @import "~bootstrap/scss/card"; // @import "~bootstrap/scss/accordion"; @import "~bootstrap/scss/breadcrumb"; -// @import "~bootstrap/scss/pagination"; +@import "~bootstrap/scss/pagination"; @import "~bootstrap/scss/badge"; @import "~bootstrap/scss/alert"; // @import "~bootstrap/scss/progress"; diff --git a/assets/css/style.scss b/assets/css/style.scss index fcfc15b451407dd517d6926fcf31982f405f7daa..f791e13f3b4ee2f1bee5f31168b85ffc84254ac2 100644 --- a/assets/css/style.scss +++ b/assets/css/style.scss @@ -30,10 +30,33 @@ $list-group-color: var(--txt-secondary-color); $list-group-active-bg: var(--bg-secondary-color); $list-group-active-color: var(--txt-secondary-color); $list-group-border-color: var(--border-color); +$list-group-action-hover-color: var(--txt-secondary-color); +$list-group-hover-bg: var(--bg-secondary-color); // Cards $card-bg: var(--bg-secondary-color); +// Pagination +$pagination-border-color: var(--border-color); +$pagination-bg: var(--bg-menu-color); +$pagination-color: var(--txt-secondary-color); + +$pagination-hover-border-color: $pagination-border-color; +$pagination-hover-bg: var(--bg-secondary-color); +$pagination-hover-color: var(--txt-secondary-color); + +$pagination-active-border-color: $pagination-border-color; +$pagination-active-bg: var(--bg-secondary-color); +$pagination-active-color: var(--txt-secondary-color); + +$pagination-focus-border-color: $pagination-hover-border-color; +$pagination-focus-bg: $pagination-hover-bg; +$pagination-focus-color: $pagination-hover-color; + +$pagination-disabled-border-color: $pagination-border-color; +$pagination-disabled-bg: var(--bg-menu-color); +$pagination-disabled-color: var(--txt-secondary-color); + // Mark $mark-padding: 0.2em 0; $mark-bg: yellow; diff --git a/components/btn/Pagination.vue b/components/btn/Pagination.vue index 6dc4293d35e909db0896f1e6e8b3048b81996a75..a46580f7273492ece46f329f37f1777652c968ef 100644 --- a/components/btn/Pagination.vue +++ b/components/btn/Pagination.vue @@ -1,27 +1,48 @@ <template> - <div class="text-center" v-if="arrayLength > pageSize"> - <button - class="btn btn-secondary" - :class="{ - 'opacity-25': currentPage == 1 - }" - @click="prevPage" - :disabled="currentPage == 1"> - ⟨ - </button> - <span class="small px-2" - >{{ currentPage }} / {{ Math.ceil(arrayLength / pageSize) }}</span - > - <button - class="btn btn-secondary" - :class="{ - 'opacity-25': currentPage * pageSize >= arrayLength - }" - @click="nextPage" - :disabled="currentPage * pageSize >= arrayLength"> - ⟩ - </button> - </div> + <nav :aria-label="$t('pagination.title')" v-if="nbPages > 1"> + <ul class="pagination justify-content-center"> + <li class="page-item" v-if="currentPage > 2 && nbPages > 3"> + <a + class="page-link" + href="#" + :aria-label="$t('pagination.first')" + @click="firstPage($event)"> + <span aria-hidden="true">1</span> + </a> + </li> + <li class="page-item disabled" v-if="currentPage > 3 && nbPages > 3"> + <span class="page-link"><span aria-hidden="true">...</span></span> + </li> + <li + class="page-item" + v-for="index in listPagesUtiles" + :key="index" + :class="{ active: index == currentPage }"> + <a + v-if="index != currentPage" + class="page-link" + href="#" + @click="goto(index, $event)" + >{{ index }}</a + > + <span v-else class="page-link">{{ index }}</span> + </li> + <li + class="page-item disabled" + v-if="currentPage < nbPages - 2 && nbPages > 3"> + <span class="page-link"><span aria-hidden="true">...</span></span> + </li> + <li class="page-item" v-if="currentPage < nbPages - 1 && nbPages > 3"> + <a + class="page-link" + href="#" + aria-label="$t('pagination.last')" + @click="lastPage($event)"> + <span aria-hidden="true">{{ nbPages }}</span> + </a> + </li> + </ul> + </nav> </template> <script> @@ -41,14 +62,49 @@ export default { } }, methods: { - nextPage: function () { - if (this.currentPage * this.pageSize < this.arrayLength) - this.$emit("update:currentPage", this.currentPage + 1) + goto(i, e) { + e.preventDefault() + this.$emit("update:currentPage", i) }, - prevPage: function () { - if (this.currentPage > 1) - this.$emit("update:currentPage", this.currentPage - 1) + firstPage: function (e) { + e.preventDefault() + this.$emit("update:currentPage", 1) + }, + lastPage: function (e) { + e.preventDefault() + this.$emit("update:currentPage", this.nbPages) + } + }, + computed: { + nbPages() { + return Math.ceil(this.arrayLength / this.pageSize) + }, + listPagesUtiles() { + if (this.nbPages < 3) { + return [1, 2] + } + + if (this.currentPage == 1) { + return [1, 2, 3] + } + + if (this.currentPage == this.nbPages) { + return [this.nbPages - 2, this.nbPages - 1, this.nbPages] + } + + return [this.currentPage - 1, this.currentPage, this.currentPage + 1] } } } </script> + +<style lang="scss" scoped> +.pagination { + user-select: none; +} + +.disabled, +.active { + cursor: not-allowed; +} +</style> diff --git a/components/certif/List.vue b/components/certif/List.vue index df8189ae805c7f414e5bfba7bfef2a5077358f23..982ea728ebfac262c0cdc196d5b11175f6d5b594 100644 --- a/components/certif/List.vue +++ b/components/certif/List.vue @@ -4,14 +4,17 @@ <table class="table table-striped table-hover table-fixed sortable border"> <thead class="thead-light"> <tr> - <th class="p-0" @click="sort('uid')"> + <th class="p-0" @click="sort('uid')" @keyup.enter="sort('uid')"> <BtnSort :title="$t('membre.title')" fieldName="uid" :currentSort="currentSort" :currentSortDir="currentSortDir" /> </th> - <th class="p-0 td-date" @click="sort('expires_on')"> + <th + class="p-0 td-date" + @click="sort('expires_on')" + @keyup.enter="sort('expires_on')"> <BtnSort :title="$t('expire')" fieldName="expires_on" @@ -24,6 +27,7 @@ <tr v-for="certif in certifsTriees" :key="certif.uid" + tabindex="0" @click=" $router.push( localePath({ @@ -31,6 +35,14 @@ query: { hash: certif.hash } }) ) + " + @keyup.enter=" + $router.push( + localePath({ + name: 'membre', + query: { hash: certif.hash } + }) + ) "> <td class="py-1"> <div class="d-flex"> diff --git a/components/member/List.vue b/components/member/List.vue index 1e2c213115d3ba0ec69e5500377c626a32ae85f4..429c0afe75f3caca6e5264a5961d008e5c04bf3f 100644 --- a/components/member/List.vue +++ b/components/member/List.vue @@ -8,8 +8,7 @@ class="p-0" scope="col" @click="sort('uid')" - @keyup.enter="sort('uid')" - @keyup.space="sort('uid')"> + @keyup.enter="sort('uid')"> <BtnSort fieldName="uid" title="UID" @@ -20,7 +19,8 @@ scope="col" class="d-none d-lg-table-cell p-0" v-if="['favoris', 'search'].includes(type)" - @click="sort('statut')"> + @click="sort('statut')" + @keyup.enter="sort('statut')"> <BtnSort fieldName="statut" :title="$t('statut.title')" @@ -31,7 +31,8 @@ scope="col" class="td-quality d-none d-lg-table-cell p-0" v-if="['favoris', 'search'].includes(type)" - @click="sort('quality')"> + @click="sort('quality')" + @keyup.enter="sort('quality')"> <BtnSort fieldName="quality" :title="$t('membre.qualite.title')" @@ -42,7 +43,8 @@ scope="col" class="d-none d-xl-table-cell p-0" v-if="['favoris', 'search'].includes(type)" - @click="sort('dispo')"> + @click="sort('dispo')" + @keyup.enter="sort('dispo')"> <BtnSort fieldName="dispo" :title="$t('membre.dispo')" @@ -53,6 +55,7 @@ scope="col" class="td-date d-none d-sm-table-cell p-0" @click="sort('date_membership')" + @keyup.enter="sort('date_membership')" v-if="['adhesion', 'favoris', 'search'].includes(type)"> <BtnSort fieldName="date_membership" @@ -72,6 +75,7 @@ 'd-md-table-cell': type != 'certif' }" @click="sort('date_certs')" + @keyup.enter="sort('date_certs')" v-if="['certif', 'favoris', 'search'].includes(type)"> <BtnSort fieldName="date_certs" @@ -87,8 +91,13 @@ </tr> </thead> <tbody> - <tr v-for="member in membersSorted" :key="member.uid"> - <td @click="redirect(member.hash)"> + <tr + v-for="member in membersSorted" + :key="member.uid" + tabindex="0" + @click="redirect(member.hash)" + @keyup.enter="redirect(member.hash)"> + <td> <div class="d-flex"> <div class="d-flex flex-column align-items-center justify-content-evenly flex-grow-1"> @@ -126,20 +135,17 @@ </td> <td class="d-none d-lg-table-cell" - v-if="['favoris', 'search'].includes(type)" - @click="redirect(member.hash)"> + v-if="['favoris', 'search'].includes(type)"> <BadgeStatus :membre="member" /> </td> <td class="d-none d-lg-table-cell" - v-if="['favoris', 'search'].includes(type)" - @click="redirect(member.hash)"> + v-if="['favoris', 'search'].includes(type)"> <BadgeQuality :quality="member.quality.ratio" /> </td> <td class="d-none d-xl-table-cell" - v-if="['favoris', 'search'].includes(type)" - @click="redirect(member.hash)"> + v-if="['favoris', 'search'].includes(type)"> <BadgeDispo :isDispo="member.minDatePassed" :dateDispo="member.minDate" @@ -147,8 +153,7 @@ </td> <td class="d-none d-sm-table-cell" - v-if="['adhesion', 'favoris', 'search'].includes(type)" - @click="redirect(member.hash)"> + v-if="['adhesion', 'favoris', 'search'].includes(type)"> <BadgeDate :date="member.limitDate" styleDate="short" /> </td> <td @@ -157,8 +162,7 @@ 'd-sm-table-cell': type == 'certif', 'd-md-table-cell': type != 'certif' }" - v-if="['certif', 'favoris', 'search'].includes(type)" - @click="redirect(member.hash)"> + v-if="['certif', 'favoris', 'search'].includes(type)"> <BadgeDate :date="member.certsLimit" styleDate="short" /> </td> <td class="py-1" v-if="type == 'favoris'" style="width: 60px"> diff --git a/components/navigation/menu/Sidebar.vue b/components/navigation/menu/Sidebar.vue index 5971ef74796ff56d82782303dd69457b65f8ae93..e05c5d83372ea8d002aa91f75def80af27fce5fa 100644 --- a/components/navigation/menu/Sidebar.vue +++ b/components/navigation/menu/Sidebar.vue @@ -3,7 +3,7 @@ <div class="mb-4"> <nuxt-link @click.native=" - if (sreenwidth < 1200) { + if (screenwidth < 1200) { toggleMenu() } " @@ -41,7 +41,12 @@ <div class="py-3 text-center"> <button class="btn btn-secondary btn-sm" - @click="$router.push(localePath('a-propos'))"> + @click=" + if (screenwidth < 1200) { + toggleMenu() + } + $router.push(localePath('a-propos')) + "> v{{ $config.clientVersion }} | {{ $t("apropos.title") }} </button> </div> @@ -55,7 +60,7 @@ import { VERSION } from "@/graphql/queries.js" export default { data() { return { - sreenwidth: 0 + screenwidth: 0 } }, props: { @@ -66,7 +71,7 @@ export default { this.$emit("toggleMenu") }, onResize() { - this.sreenwidth = window.screen.width + this.screenwidth = window.innerWidth } }, apollo: { @@ -78,7 +83,7 @@ export default { } }, mounted() { - this.sreenwidth = window.screen.width + this.screenwidth = window.innerWidth this.$nextTick(function () { this.onResize() }) diff --git a/pages/previsions/index.vue b/pages/previsions/index.vue index b9c9c58f9ac6698bb35b0058f6efe3fdc133419c..00c88502c2e84076e36e0c4085359e745e4e35a3 100644 --- a/pages/previsions/index.vue +++ b/pages/previsions/index.vue @@ -51,6 +51,7 @@ <tr v-for="forecast in wwResult.forecastsByNames" :key="forecast.member.uid" + tabindex="0" @click=" $router.push( localePath({ @@ -58,9 +59,18 @@ query: { hash: forecast.member.hash } }) ) + " + @keyup.enter=" + $router.push( + localePath({ + name: 'membre', + query: { hash: forecast.member.hash } + }) + ) "> <td class="td-uid"> - <span class="text-truncate mw-100 d-inline-block"> + <span + class="text-truncate mw-100 d-inline-block txt-secondary"> <span v-if=" $favourites.list.includes(forecast.member.uid) @@ -75,7 +85,7 @@ v-for="date in forecast.forecasts" :key="date.date"> <div - class="text-center" + class="text-center txt-secondary" v-if="date.date < 9999999999"> {{ $d(new Date(date.date * 1000), "short") }} {{ $t("time.a") }} {{ @@ -105,17 +115,19 @@ v-for="forecast in wwResult.forecastsByDates" :key="forecast.date"> <td class="text-center" v-if="forecast.date < 9999999999"> - {{ $d(new Date(forecast.date * 1000), "short") }} - {{ $t("time.a") }} {{ - $d(new Date(forecast.date * 1000), "hour").replace( - " ", - " " - ) - }} + <span class="txt-secondary"> + {{ $d(new Date(forecast.date * 1000), "short") }} + {{ $t("time.a") }} {{ + $d(new Date(forecast.date * 1000), "hour").replace( + " ", + " " + ) + }} + </span> </td> <td v-else>N/A</td> <td class="p-0 td-uid"> - <div class="list-group"> + <div class="list-group rounded-0"> <nuxt-link class="list-group-item list-group-item-action border-0 d-flex justify-content-between align-items-center" :to=" @@ -276,6 +288,11 @@ export default { </script> <style lang="scss" scoped> +.table-hover > tbody > tr:focus > * { + --bs-table-accent-bg: var(--bs-table-hover-bg); + color: var(--bs-table-hover-color); +} + .p-date, .list-group-item { flex-direction: column; @@ -285,15 +302,6 @@ export default { } } -.list-group-item { - background: transparent; - - &:hover { - background: var(--bg-secondary-color); - color: var(--txt-primary-color); - } -} - .td-uid { width: 50%; } diff --git a/plugins/favourites.js b/plugins/favourites.js index 766b4c538b09f4e0aae2805833590ed3b55ccf7d..36616e66eab13c54231d2a9435e7efa7608c5015 100644 --- a/plugins/favourites.js +++ b/plugins/favourites.js @@ -6,6 +6,7 @@ export default (context, inject) => { : [] let toggleFavourite = (uid, e) => { + e.stopPropagation() if (!context.$favourites.list.includes(uid)) { context.$favourites.list.push(uid) } else {