Skip to content
Snippets Groups Projects
Commit ab315cf2 authored by Timothee P's avatar Timothee P :sunflower:
Browse files

create switch buttons component to fix mobile view & fix style and others...

parent 0b44192f
No related branches found
No related tags found
No related merge requests found
......@@ -32,6 +32,9 @@ main {
.important-flex {
display: flex !important;
}
.pointer:hover {
cursor: pointer;
}
/* ---------------------------------- */
/* MAIN */
/* ---------------------------------- */
......
<template>
<div
class="switch-buttons pointer"
:data-tooltip="`Passer en mode ${massMode === 'modify' ? 'suppression':'édition'}`"
@click="switchMode"
>
<div><i :class="['icon pencil', {disabled: massMode !== 'modify'}]" /></div>
<span class="grey">|&nbsp;</span>
<div><i :class="['icon trash', {disabled: massMode !== 'delete'}]" /></div>
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex';
export default {
name: 'FeatureListMassToggle',
computed: {
...mapState('feature', ['massMode'])
},
methods: {
...mapMutations('feature', [
'TOGGLE_MASS_MODE',
'UPDATE_CHECKED_FEATURES',
'UPDATE_CLICKED_FEATURES']),
switchMode() {
this.TOGGLE_MASS_MODE(this.massMode === 'modify' ? 'delete' : 'modify');
this.UPDATE_CLICKED_FEATURES([]);
this.UPDATE_CHECKED_FEATURES([]);
}
},
};
</script>
<style scoped>
.switch-buttons {
display: flex;
justify-content: center;
align-items: baseline;
}
.grey {
color: #bbbbbb;
}
</style>
\ No newline at end of file
<template>
<div
data-tab="list"
class="dataTables_wrapper no-footer"
>
<table
id="table-features"
class="ui compact table dataTable"
<div>
<div class="table-mobile-buttons left-align">
<FeatureListMassToggle />
</div>
<div
data-tab="list"
class="dataTables_wrapper no-footer"
>
<thead>
<tr>
<th class="dt-center">
<div
class="switch-buttons pointer"
:data-tooltip="`Passer en mode ${mode === 'modify' ? 'suppression':'édition'}`"
@click="switchMode"
>
<div><i :class="['icon pencil', {disabled: mode !== 'modify'}]" /></div>
<span class="grey">|&nbsp;</span>
<div><i :class="['icon trash', {disabled: mode !== 'delete'}]" /></div>
</div>
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('status')"
>
Statut
<i
:class="{
down: isSortedAsc('status'),
up: isSortedDesc('status'),
}"
class="icon sort"
/>
</div>
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('feature_type')"
>
Type
<i
:class="{
down: isSortedAsc('feature_type'),
up: isSortedDesc('feature_type'),
}"
class="icon sort"
/>
</div>
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('title')"
<table
id="table-features"
class="ui compact table unstackable dataTable"
>
<thead>
<tr>
<th class="dt-center">
<FeatureListMassToggle />
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('status')"
>
Statut
<i
:class="{
down: isSortedAsc('status'),
up: isSortedDesc('status'),
}"
class="icon sort"
/>
</div>
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('feature_type')"
>
Type
<i
:class="{
down: isSortedAsc('feature_type'),
up: isSortedDesc('feature_type'),
}"
class="icon sort"
/>
</div>
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('title')"
>
Nom
<i
:class="{
down: isSortedAsc('title'),
up: isSortedDesc('title'),
}"
class="icon sort"
/>
</div>
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('updated_on')"
>
Dernière modification
<i
:class="{
down: isSortedAsc('updated_on'),
up: isSortedDesc('updated_on'),
}"
class="icon sort"
/>
</div>
</th>
<th
v-if="user"
class="dt-center"
>
Nom
<i
:class="{
down: isSortedAsc('title'),
up: isSortedDesc('title'),
}"
class="icon sort"
/>
</div>
</th>
<th class="dt-center">
<div
class="pointer"
@click="changeSort('updated_on')"
<div
class="pointer"
@click="changeSort('display_creator')"
>
Auteur
<i
:class="{
down: isSortedAsc('display_creator'),
up: isSortedDesc('display_creator'),
}"
class="icon sort"
/>
</div>
</th>
<th
v-if="user"
class="dt-center"
>
Dernière modification
<i
:class="{
down: isSortedAsc('updated_on'),
up: isSortedDesc('updated_on'),
}"
class="icon sort"
/>
</div>
</th>
<th
v-if="user"
class="dt-center"
<div
class="pointer"
@click="changeSort('display_last_editor')"
>
Dernier éditeur
<i
:class="{
down: isSortedAsc('display_last_editor'),
up: isSortedDesc('display_last_editor'),
}"
class="icon sort"
/>
</div>
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(feature, index) in paginatedFeatures"
:key="index"
>
<div
class="pointer"
@click="changeSort('display_creator')"
>
Auteur
<i
:class="{
down: isSortedAsc('display_creator'),
up: isSortedDesc('display_creator'),
<td class="dt-center">
<div
:class="['ui checkbox', {disabled: !checkRights(feature)}]"
>
<input
:id="feature.id"
v-model="checked"
type="checkbox"
:value="feature.id"
:disabled="!checkRights(feature)"
name="select"
@input="storeClickedFeature(feature)"
>
<label for="select" />
</div>
</td>
<td class="dt-center">
<div v-if="feature.properties.status.value === 'archived'">
<span data-tooltip="Archivé">
<i class="grey archive icon" />
</span>
</div>
<div v-else-if="feature.properties.status.value === 'pending'">
<span data-tooltip="En attente de publication">
<i class="teal hourglass outline icon" />
</span>
</div>
<div v-else-if="feature.properties.status.value === 'published'">
<span data-tooltip="Publié">
<i class="olive check icon" />
</span>
</div>
<div v-else-if="feature.properties.status.value === 'draft'">
<span data-tooltip="Brouillon">
<i class="orange pencil alternate icon" />
</span>
</div>
</td>
<td class="dt-center">
<router-link
:to="{
name: 'details-type-signalement',
params: {
feature_type_slug: feature.properties.feature_type.slug,
},
}"
class="icon sort"
/>
</div>
</th>
<th
v-if="user"
class="dt-center"
>
<div
class="pointer"
@click="changeSort('display_last_editor')"
>
Dernier éditeur
<i
:class="{
down: isSortedAsc('display_last_editor'),
up: isSortedDesc('display_last_editor'),
>
{{ feature.properties.feature_type.title }}
</router-link>
</td>
<td class="dt-center">
<router-link
:to="{
name: 'details-signalement',
params: {
slug_type_signal: feature.properties.feature_type.slug,
slug_signal: feature.properties.slug || feature.id,
},
}"
class="icon sort"
/>
</div>
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(feature, index) in paginatedFeatures"
:key="index"
>
<td class="dt-center">
<div
:class="['ui checkbox', {disabled: !checkRights(feature)}]"
>
<input
:id="feature.id"
v-model="checked"
type="checkbox"
:value="feature.id"
:disabled="!checkRights(feature)"
name="select"
@input="storeClickedFeature(feature)"
>
<label for="select" />
</div>
</td>
<td class="dt-center">
<div
v-if="feature.properties.status.value === 'archived'"
data-tooltip="Archivé"
>
<i class="grey archive icon" />
</div>
<div
v-else-if="feature.properties.status.value === 'pending'"
data-tooltip="En attente de publication"
>
<i class="teal hourglass outline icon" />
</div>
<div
v-else-if="feature.properties.status.value === 'published'"
data-tooltip="Publié"
>
<i class="olive check icon" />
</div>
<div
v-else-if="feature.properties.status.value === 'draft'"
data-tooltip="Brouillon"
{{ getFeatureDisplayName(feature) }}
</router-link>
</td>
<td class="dt-center">
{{ feature.properties.updated_on }}
</td>
<td
v-if="user"
class="dt-center"
>
<i class="orange pencil alternate icon" />
</div>
</td>
<td class="dt-center">
<router-link
:to="{
name: 'details-type-signalement',
params: {
feature_type_slug: feature.properties.feature_type.slug,
},
}"
{{ getUserName(feature) }}
</td>
<td
v-if="user"
class="dt-center"
>
{{ feature.properties.feature_type.title }}
</router-link>
</td>
<td class="dt-center">
<router-link
:to="{
name: 'details-signalement',
params: {
slug_type_signal: feature.properties.feature_type.slug,
slug_signal: feature.properties.slug || feature.id,
},
}"
>
{{ getFeatureDisplayName(feature) }}
</router-link>
</td>
<td class="dt-center">
{{ feature.properties.updated_on }}
</td>
<td
v-if="user"
class="dt-center"
>
{{ getUserName(feature) }}
</td>
<td
v-if="user"
class="dt-center"
>
{{ feature.properties.display_last_editor }}
</td>
</tr>
<tr
v-if="featuresCount === 0"
class="odd"
>
<td
colspan="5"
class="dataTables_empty"
valign="top"
{{ feature.properties.display_last_editor }}
</td>
</tr>
<tr
v-if="featuresCount === 0"
class="odd"
>
Aucune donnée disponible
</td>
</tr>
</tbody>
</table>
<div
v-if="pageNumbers.length > 1"
id="table-features_info"
class="dataTables_info"
role="status"
aria-live="polite"
>
Affichage de l'élément {{ pagination.start + 1 }} à
{{ displayedPageEnd }}
sur {{ featuresCount }} éléments
</div>
<div
v-if="pageNumbers.length > 1"
id="table-features_paginate"
class="dataTables_paginate paging_simple_numbers"
>
<a
id="table-features_previous"
:class="[
'paginate_button previous',
{ disabled: pagination.currentPage === 1 },
]"
aria-controls="table-features"
data-dt-idx="0"
tabindex="0"
@click="$emit('update:page', 'previous')"
>Précédent</a>
<span>
<span v-if="pagination.currentPage >= 5">
<a
key="page1"
class="paginate_button"
aria-controls="table-features"
data-dt-idx="1"
tabindex="0"
@click="$emit('update:page', 1)"
>{{ 1 }}</a>
<span class="ellipsis"></span>
</span>
<td
colspan="5"
class="dataTables_empty"
valign="top"
>
Aucune donnée disponible
</td>
</tr>
</tbody>
</table>
<div
v-if="pageNumbers.length > 1"
id="table-features_info"
class="dataTables_info"
role="status"
aria-live="polite"
>
Affichage de l'élément {{ pagination.start + 1 }} à
{{ displayedPageEnd }}
sur {{ featuresCount }} éléments
</div>
<div
v-if="pageNumbers.length > 1"
id="table-features_paginate"
class="dataTables_paginate paging_simple_numbers"
>
<a
v-for="pageNumber in displayedPageNumbers"
:key="'page' + pageNumber"
id="table-features_previous"
:class="[
'paginate_button',
{ current: pageNumber === pagination.currentPage },
'paginate_button previous',
{ disabled: pagination.currentPage === 1 },
]"
aria-controls="table-features"
data-dt-idx="1"
data-dt-idx="0"
tabindex="0"
@click="$emit('update:page', pageNumber)"
>{{ pageNumber }}</a>
<span v-if="(lastPageNumber - pagination.currentPage) >= 4">
<span class="ellipsis"></span>
@click="$emit('update:page', 'previous')"
>Précédent</a>
<span>
<span v-if="pagination.currentPage >= 5">
<a
key="page1"
class="paginate_button"
aria-controls="table-features"
data-dt-idx="1"
tabindex="0"
@click="$emit('update:page', 1)"
>{{ 1 }}</a>
<span class="ellipsis"></span>
</span>
<a
:key="'page' + lastPageNumber"
class="paginate_button"
v-for="pageNumber in displayedPageNumbers"
:key="'page' + pageNumber"
:class="[
'paginate_button',
{ current: pageNumber === pagination.currentPage },
]"
aria-controls="table-features"
data-dt-idx="1"
tabindex="0"
@click="$emit('update:page', lastPageNumber)"
>{{ lastPageNumber }}</a>
@click="$emit('update:page', pageNumber)"
>{{ pageNumber }}</a>
<span v-if="(lastPageNumber - pagination.currentPage) >= 4">
<span class="ellipsis"></span>
<a
:key="'page' + lastPageNumber"
class="paginate_button"
aria-controls="table-features"
data-dt-idx="1"
tabindex="0"
@click="$emit('update:page', lastPageNumber)"
>{{ lastPageNumber }}</a>
</span>
</span>
</span>
<a
id="table-features_next"
:class="[
'paginate_button next',
{ disabled: pagination.currentPage === pageNumbers.length },
]"
aria-controls="table-features"
data-dt-idx="7"
tabindex="0"
@click="$emit('update:page', 'next')"
>Suivant</a>
<a
id="table-features_next"
:class="[
'paginate_button next',
{ disabled: pagination.currentPage === pageNumbers.length },
]"
aria-controls="table-features"
data-dt-idx="7"
tabindex="0"
@click="$emit('update:page', 'next')"
>Suivant</a>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations } from 'vuex';
import FeatureListMassToggle from '@/components/feature/FeatureListMassToggle';
import { mapState, mapGetters } from 'vuex';
export default {
name: 'FeatureListTable',
components: {
FeatureListMassToggle,
},
props: {
paginatedFeatures: {
type: Array,
......@@ -316,10 +314,6 @@ export default {
type: Array,
default: null,
},
clickedFeatures: {
type: Array,
default: null,
},
featuresCount: {
type: Number,
default: 0,
......@@ -332,16 +326,13 @@ export default {
type: Object,
default: null,
},
mode: {
type: String,
default: null,
}
},
computed: {
...mapGetters(['permissions']),
...mapState(['user', 'USER_LEVEL_PROJECTS']),
...mapState('projects', ['project']),
...mapState('feature', ['clickedFeatures', 'massMode']),
userStatus() {
return this.USER_LEVEL_PROJECTS[this.$route.params.slug];
......@@ -396,12 +387,20 @@ export default {
},
destroyed() {
this.$store.commit('feature/UPDATE_CHECKED_FEATURES', []);
this.UPDATE_CHECKED_FEATURES([]);
},
methods: {
...mapMutations('feature', [
'UPDATE_CLICKED_FEATURES',
'UPDATE_CHECKED_FEATURES',
]),
storeClickedFeature(feature) {
this.$emit('update:clickedFeatures', [...this.clickedFeatures, { feature_id: feature.id, feature_type: feature.properties.feature_type.slug }]);
this.UPDATE_CLICKED_FEATURES([
...this.clickedFeatures,
{ feature_id: feature.id, feature_type: feature.properties.feature_type.slug }
]);
},
canDeleteFeature(feature) {
......@@ -428,7 +427,7 @@ export default {
},
checkRights(feature) {
switch (this.mode) {
switch (this.massMode) {
case 'modify':
return this.canEditFeature(feature);
case 'delete':
......@@ -436,12 +435,6 @@ export default {
}
},
switchMode() {
this.$emit('update:mode', this.mode === 'modify' ? 'delete' : 'modify');
this.$emit('update:clickedFeatures', []);
this.$store.commit('feature/UPDATE_CHECKED_FEATURES', []);
},
getUserName(feature) {
if (!feature.properties.creator) {
return ' ---- ';
......@@ -565,15 +558,6 @@ table.dataTable th.dt-center, table.dataTable td.dt-center, table.dataTable td.d
i.icon.sort:not(.down):not(.up) {
color: rgb(220, 220, 220);
}
.pointer:hover {
cursor: pointer;
}
.switch-buttons {
display: flex;
justify-content: center;
align-items: baseline;
}
.grey {
color: #bbbbbb;
......@@ -582,13 +566,28 @@ i.icon.sort:not(.down):not(.up) {
.ui.dropdown .menu .left.menu, .ui.dropdown > .left.menu .menu {
margin-right: 0 !important;
}
.table-mobile-buttons {
margin-bottom: 1em;
}
@media only screen and (min-width: 761px) {
.table-mobile-buttons {
display: none !important;
}
}
/*
Max width before this PARTICULAR table gets nasty
This query will take effect for any screen smaller than 760px
and also iPads specifically.
*/
@media only screen and (max-width: 760px),
(min-device-width: 768px) and (max-device-width: 1024px) {
@media only screen and (max-width: 760px) {
.table-mobile-buttons {
display: flex !important;
}
/* hide table border */
.ui.table {
border: none !important;
}
/* Force table to not be like tables anymore */
table,
thead,
......@@ -606,8 +605,12 @@ and also iPads specifically.
left: -9999px;
}
tr {
tr { /* style as a card */
border: 1px solid #ccc;
border-radius: 7px;
margin-bottom: 3vh;
padding: 0 1vw .5em 1vw;
box-shadow: rgba(50, 50, 50, 0.1) 2px 5px 10px ;
}
td {
......@@ -617,7 +620,19 @@ and also iPads specifically.
position: relative;
padding-left: 50%;
}
.ui.table tr td {
border-top: none;
}
.ui.compact.table td {
padding: .2em;
}
td:nth-of-type(1) {
border: none !important;
padding: .25em !important;
}
td:nth-of-type(7) {
border-bottom: none !important;
}
td:before {
/* Now like a table header */
position: absolute;
......@@ -628,7 +643,6 @@ and also iPads specifically.
padding-right: 10px;
white-space: nowrap;
}
/*
Label the data
*/
......@@ -650,20 +664,29 @@ and also iPads specifically.
td:nth-of-type(6):before {
content: "Auteur";
}
td:nth-of-type(7):before {
content: "Dernier éditeur";
}
table.dataTable th.dt-center, table.dataTable td.dt-center, table.dataTable td.dataTables_empty {
text-align: right;
}
#table-features {
margin-left: 1em;
width: calc(100% - 1em);
}
.ui.checkbox {
position: absolute;
left: -1.75em;
top: 5em;
left: calc(-1vw - .75em);
top: -.75em;
}
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_paginate {
width: 100%;
text-align: center;
margin: .5em 0;
}
}
@media only screen and (max-width: 410px) {
.ui.table tr td {
border: none;
}
}
</style>
\ No newline at end of file
......@@ -106,7 +106,7 @@ export default new Vuex.Store({
CLEAR_RELOAD_INTERVAL_ID(state) {
clearInterval(state.reloadIntervalId);
state.reloadIntervalId = null;
}
},
},
getters: {
......
......@@ -8,6 +8,7 @@ const feature = {
attachmentFormset: [],
attachmentsToDelete: [],
checkedFeatures: [],
clickedFeatures: [],
extra_form: [],
features: [],
features_count: 0,
......@@ -15,6 +16,7 @@ const feature = {
form: null,
linkedFormset: [],
linked_features: [],
massMode: 'modify',
statusChoices: [
{
name: 'Brouillon',
......@@ -100,7 +102,13 @@ const feature = {
},
UPDATE_CHECKED_FEATURES(state, checkedFeatures) {
state.checkedFeatures = checkedFeatures;
}
},
UPDATE_CLICKED_FEATURES(state, clickedFeatures) {
state.clickedFeatures = clickedFeatures;
},
TOGGLE_MASS_MODE(state, payload) {
state.massMode = payload;
},
},
getters: {
},
......
......@@ -71,7 +71,7 @@
</div>
<div
v-if="checkedFeatures.length > 0 && mode === 'modify'"
v-if="checkedFeatures.length > 0 && massMode === 'modify'"
class="ui dropdown button compact button-hover-green margin-left-25"
data-tooltip="Modifier le statut des Signalements"
data-position="bottom right"
......@@ -100,7 +100,7 @@
</div>
<div
v-if="checkedFeatures.length > 0 && mode === 'delete'"
v-if="checkedFeatures.length > 0 && massMode === 'delete'"
class="ui button compact button-hover-red margin-left-25"
data-tooltip="Effacer tous les types de signalements sélectionnés"
data-position="bottom right"
......@@ -192,8 +192,6 @@
:paginated-features="paginatedFeatures"
:checked-features.sync="checkedFeatures"
:features-count="featuresCount"
:clicked-features.sync="clickedFeatures"
:mode.sync="mode"
:pagination="pagination"
:sort="sort"
@update:page="handlePageChange"
......@@ -237,7 +235,7 @@
</template>
<script>
import { mapGetters, mapState, mapActions } from 'vuex';
import { mapGetters, mapState, mapActions, mapMutations } from 'vuex';
import { mapUtil } from '@/assets/js/map-util.js';
import featureAPI from '@/services/feature-api';
import SidebarLayers from '@/components/map-layers/SidebarLayers';
......@@ -257,7 +255,6 @@ export default {
data() {
return {
clickedFeatures: [],
currentLayer: null,
featuresCount: 0,
form: {
......@@ -273,7 +270,6 @@ export default {
lng: null,
map: null,
modalAllDeleteOpen: false,
mode: 'modify',
next: null,
paginatedFeatures: [],
pagination: {
......@@ -305,7 +301,9 @@ export default {
]),
...mapState('feature', [
'checkedFeatures',
'clickedFeatures',
'statusChoices',
'massMode',
]),
...mapState('feature_type', [
'feature_types',
......@@ -409,6 +407,10 @@ export default {
'SEND_FEATURE'
]),
...mapMutations('feature', [
'UPDATE_CHECKED_FEATURES'
]),
toggleAddFeature() {
this.showAddFeature = !this.showAddFeature;
this.showModifyStatus = false;
......@@ -444,7 +446,9 @@ export default {
newStatus
}).then((response) => {
if (response && response.data && response.status === 200) {
this.checkedFeatures.splice(this.checkedFeatures.indexOf(response.data.id), 1);
let newCheckedFeatures = [...this.checkedFeatures];
newCheckedFeatures.splice(this.checkedFeatures.indexOf(response.data.id), 1);
this.UPDATE_CHECKED_FEATURES(newCheckedFeatures);
this.modifyStatus(newStatus);
} else {
this.$store.commit('DISPLAY_MESSAGE', {
......@@ -725,6 +729,10 @@ export default {
margin-right: 0 !important;
}
#button-dropdown {
z-index: 1;
}
@media screen and (min-width: 767px) {
.twelve-wide {
width: 75% !important;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment