Skip to content

Commit

Permalink
feat: vue mobile pour le tableau
Browse files Browse the repository at this point in the history
Signed-off-by: Maud Royer <hello@maudroyer.fr>
  • Loading branch information
jillro committed Apr 2, 2024
1 parent c54bf0e commit 190e177
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 158 deletions.
285 changes: 174 additions & 111 deletions src/components/Features/FeatureGroup.vue
Original file line number Diff line number Diff line change
@@ -1,68 +1,97 @@
<template>
<tbody>
<tr @click.stop="open = !open" class="clickable group-header">
<td>
<td class="selection">
<div class="fr-checkbox-group single-checkbox">
<input type="checkbox" :id="'radio-'+ featureGroup.key" :checked="allSelected" @click="toggleFeatureGroup" />
<label class="fr-label" :for="'radio-'+ featureGroup.key" />
</div>
</td>
<td><span class="fr-icon fr-icon-arrow-down-s-line" :aria-checked="open" aria-role="button" /></td>
<th scope="row" colspan="2" :data-group-id="featureGroup.key">{{ featureGroup.label }}</th>
<td class="numeric">{{ inHa(featureGroup.surface) }}&nbsp;ha</td>
<td class="accordion"><span class="fr-icon fr-icon-arrow-down-s-line" :aria-checked="open" aria-role="button" /></td>
<th class="labels" scope="row" :data-group-id="featureGroup.key">{{ featureGroup.label }}</th>
<td class="surface numeric">{{ inHa(featureGroup.surface) }}&nbsp;ha</td>
<td class="actions">
<span class="fr-btn fr-btn--tertiary-no-outline fr-icon-warning-fill fr-icon--warning" :title="`${groupErrors} parcelles à amender`" v-if="groupErrors" />
<span
v-if="groupErrors"
class="fr-btn fr-btn--tertiary-no-outline fr-icon-warning-fill fr-icon--warning fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl"
:title="`${groupErrors} parcelles à amender`"
/>
</td>
</tr>
<tr :hidden="!open" class="intermediate-header">
<th scope="col" colspan="2"></th>
<th scope="col" v-if="isGroupedByCulture">Nom</th>
<th scope="col" v-else>Culture</th>
<th scope="col">Certification</th>
<th scope="col" colspan="2"></th>
</tr>
<tr class="parcelle clickable" :class="{'parcelle--is-new': feature.id === Number(route.query?.new)}" :id="'parcelle-' + feature.id" :hidden="!open" v-for="feature in featureGroup.features" :key="feature.id" @mouseover="hoveredId = feature.id" :aria-current="feature.id === hoveredId ? 'location' : null">
<th scope="row">
<div class="fr-checkbox-group single-checkbox">
<input type="checkbox" :id="'radio-' + feature.id" :checked="selectedIds.includes(feature.id)" @click="toggleSingleSelected(feature.id)" />
<label class="fr-label" :for="'radio-' + feature.id" />
</div>
</th>
<td @click="toggleEditForm(feature.id)"></td>
<td @click="toggleEditForm(feature.id)" v-if="isGroupedByCulture">
<span class="culture-name">{{ featureName(feature) }}</span>
<small class="feature-precision" v-if="feature.properties.cultures.length > 1">Multi-culture</small>
</td>
<td @click="toggleEditForm(feature.id)" v-else>
<span class="culture-type" v-if="feature.properties.cultures.length > 1">
Multi-cultures<span class="fr-sr-only"> : </span>
<small class="feature-precision" v-for="(culture, i) in feature.properties.cultures" :key="i">
<span v-if="i" class="fr-sr-only">, </span>{{ cultureLabel(culture) }}
</small>
</span>
<span class="culture-name" v-else>{{ cultureLabel(feature.properties.cultures[0]) }}</span>
<small class="feature-precision">{{ featureName(feature) }}</small>
</td>
<td @click="toggleEditForm(feature.id)">
<ConversionLevel :feature="feature" with-date />
</td>
<td @click="toggleEditForm(feature.id)" class="numeric">{{ inHa(surface(feature)) }}&nbsp;ha</td>
<td class="actions">
<button type="button" :class="{'fr-btn': true, 'fr-btn--tertiary-no-outline': true, 'fr-icon-edit-line': true /*!featuresSets.byFeature(feature.id, true).size, 'fr-icon-edit-box-fill fr-icon--warning': featuresSets.byFeature(feature.id, true).size*/}" @click="toggleEditForm(feature.id)">
Modifier
</button>
<ActionDropdown>
<router-link v-if="permissions.canChangeGeometry" :to="`/exploitations/${operatorStore.operator.numeroBio}/${recordStore.record.record_id}/modifier/${feature.id}`" type="button" class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
Modifier le contour
</router-link>
<button v-else type="button" disabled class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
Modifier le contour
</button>
<button type="button" @click.prevent="toggleDeleteForm(feature.id)" :disabled="!permissions.canDeleteFeature" class="fr-btn fr-btn--tertiary-no-outline fr-icon-delete-line btn--error fr-text--sm">
Supprimer la parcelle
</button>
</ActionDropdown>
<tr>
<td colspan="7">
<table class="fr-table group-table">
<colgroup>
<col class="selection" />
<col class="labels" />
<col class="certification" />
<col class="surface" />
<col class="actions" />
</colgroup>
<tr :hidden="!open" class="intermediate-header">
<th scope="col"></th>
<th scope="col" v-if="isGroupedByCulture">Nom</th>
<th scope="col" v-else>Culture</th>
<th scope="col" class="certification">
<span class=" fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">Certification</span>
</th>
<th scope="col" class="surface">
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">Surface</span>
</th>
<th scope="col" class="actions">Actions</th>
</tr>
<tr class="parcelle clickable" :class="{'parcelle--is-new': feature.id === Number(route.query?.new)}" :id="'parcelle-' + feature.id" :hidden="!open" v-for="feature in featureGroup.features" :key="feature.id" @mouseover="hoveredId = feature.id" :aria-current="feature.id === hoveredId ? 'location' : null">
<th scope="row">
<div class="fr-checkbox-group single-checkbox">
<input type="checkbox" :id="'radio-' + feature.id" :checked="selectedIds.includes(feature.id)" @click="toggleSingleSelected(feature.id)" />
<label class="fr-label" :for="'radio-' + feature.id" />
</div>
</th>
<td @click="toggleEditForm(feature.id)" v-if="isGroupedByCulture">
<span class="culture-name">{{ featureName(feature) }}</span>
<small class="feature-precision" v-if="feature.properties.cultures.length > 1">Multi-culture</small>
<small class="feature-precision fr-hidden-sm fr-hidden-md fr-hidden-lg fr-hidden-xl">
<ConversionLevel :feature="feature" with-date /><br />
{{ inHa(surface(feature)) }}&nbsp;ha
</small>
</td>
<td @click="toggleEditForm(feature.id)" v-else>
<span class="culture-type" v-if="feature.properties.cultures.length > 1">
Multi-cultures<span class="fr-sr-only"> : </span>
<small class="feature-precision" v-for="(culture, i) in feature.properties.cultures" :key="i">
<span v-if="i" class="fr-sr-only">, </span>{{ cultureLabel(culture) }}
</small>
</span>
<span class="culture-name" v-else>{{ cultureLabel(feature.properties.cultures[0]) }}</span>
<small class="feature-precision">{{ featureName(feature) }}</small>
</td>
<td @click="toggleEditForm(feature.id)">
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">
<ConversionLevel :feature="feature" with-date />
</span>
</td>
<td @click="toggleEditForm(feature.id)" class="numeric">
<span class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl">
{{ inHa(surface(feature)) }}&nbsp;ha
</span>
</td>
<td class="actions">
<button type="button" class="fr-hidden fr-unhidden-sm fr-unhidden-md fr-unhidden-lg fr-unhidden-xl" :class="{'fr-btn': true, 'fr-btn--tertiary-no-outline': true, 'fr-icon-edit-line': true }" @click="toggleEditForm(feature.id)" aria-label="Modifier" />
<ActionDropdown>
<router-link v-if="permissions.canChangeGeometry" :to="`/exploitations/${operatorStore.operator.numeroBio}/${recordStore.record.record_id}/modifier/${feature.id}`" type="button" class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
Modifier le contour
</router-link>
<button v-else type="button" disabled class="fr-btn fr-btn--tertiary-no-outline fr-icon-geometry fr-text--sm">
Modifier le contour
</button>
<button type="button" @click.prevent="toggleDeleteForm(feature.id)" :disabled="!permissions.canDeleteFeature" class="fr-btn fr-btn--tertiary-no-outline fr-icon-delete-line btn--error fr-text--sm">
Supprimer la parcelle
</button>
</ActionDropdown>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -141,81 +170,115 @@ watch(selectedIds, (selectedIds, prevSelectedIds) => {
</script>
<style scoped>
.fr-table tr.intermediate-header {
background-size: 100% 2px;
background-repeat: no-repeat;
background-image: linear-gradient(0deg, var(--border-plain-grey), var(--border-plain-grey));
.labels {
min-width: 100%;
}
.fr-table tr.intermediate-header th {
background-color: var(--background-default-grey);
color: var(--text-mention-grey);
border-bottom: 1px solid ;
padding-top: .75rem;
padding-bottom: .75rem;
}
.fr-table td.numeric,
.fr-table th.numeric {
font-variant-numeric: tabular-nums;
text-align: right !important;
}
.fr-table tr.group-header :is(td, th),
.fr-table tr.intermediate-header th,
.fr-table tr.parcelle :is(td, th) {
padding: .6rem;
}
.actions {
--hover: transparent;
--active: transparent;
.fr-table tr.parcelle {
background-color: var(--background-alt-blue-france);
}
.fr-table tr.parcelle:nth-child(2n) {
background-color: var(--background-default-grey);
}
.fr-table tr.parcelle:last-child {
/* same as .fr-table--bordered tbody tr */
background-size: 100% 2px;
background-image: linear-gradient(180deg, var(--grey-625-425), var(--grey-625-425));
}
position: relative;
text-align: left;
white-space: nowrap;
}
.fr-table tr.parcelle :where(.culture-type, .culture-name) {
display: block;
}
.fr-icon--warning {
color: var(--text-default-error);
}
.fr-table tr.parcelle span > .feature-precision {
display: block;
}
.fr-icon-geometry::before {
mask-image: url(@/assets/icon-geometry.svg);
}
tr.group-header td,
tr.group-header th,
tr.intermediate-header th,
tr.parcelle td,
tr.parcelle th {
padding: .6rem;
.fr-table tr.parcelle td > .feature-precision {
color: var(--text-mention-grey);
&:has(span.fr-hidden.fr-unhidden-sm) {
@media (max-width: 579px) {
padding: 0;
}
}
}
td.numeric,
th.numeric {
font-variant-numeric: tabular-nums;
text-align: right !important;
}
.fr-table tr.parcelle--is-new,
.fr-table tr.parcelle--is-new:nth-child(2n) {
background-color: var(--green-tilleul-verveine-975-75);
tr.group-header td.actions {
padding: 0;
}
td:has(table) {
padding: 0;
background-color: #fff;
}
.group-table {
margin: 0;
padding: 0;
width: 100%;
overflow: visible;
& .selection {
min-width: 2.5rem;
}
}
.fr-icon[aria-checked="true"]::before {
transform: rotate(180deg);
.group-table tr.intermediate-header {
background-size: 100% 2px;
background-repeat: no-repeat;
background-image: linear-gradient(0deg, var(--border-plain-grey), var(--border-plain-grey));
}
table tr[aria-current="location"] {
background-color: var(--background-alt-blue-france-hover) !important;
.fr-table tr.intermediate-header th {
background-color: var(--background-default-grey);
color: var(--text-mention-grey);
border-bottom: 1px solid ;
padding-top: .75rem;
padding-bottom: .75rem;
}
.actions {
--hover: transparent;
--active: transparent;
.group-table tr.parcelle {
background-color: var(--background-alt-blue-france);
}
.group-table tr.parcelle:nth-child(2n) {
background-color: var(--background-default-grey);
}
.group-table tr.parcelle:last-child {
/* same as .fr-table--bordered tbody tr */
background-size: 100% 2px;
background-image: linear-gradient(180deg, var(--grey-625-425), var(--grey-625-425));
}
position: relative;
text-align: left;
white-space: nowrap;
.group-table tr.parcelle :where(.culture-type, .culture-name) {
display: block;
}
.fr-icon--warning {
color: var(--text-default-error);
.group-table tr.parcelle span > .feature-precision {
display: block;
}
.fr-icon-geometry::before {
mask-image: url(@/assets/icon-geometry.svg);
.group-table tr.parcelle td > .feature-precision {
color: var(--text-mention-grey);
}
.group-table tr.parcelle--is-new,
.group-table tr.parcelle--is-new:nth-child(2n) {
background-color: var(--green-tilleul-verveine-975-75);
}
.fr-icon[aria-checked="true"]::before {
transform: rotate(180deg);
}
table tr[aria-current="location"] {
background-color: var(--background-alt-blue-france-hover) !important;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {

import record from './__fixtures__/record-with-features.json' assert { type: 'json' }
import EditForm from "@/components/Features/SingleItemCertificationBodyForm.vue"
import TableComponent from "./Table.vue"
import TableComponent from "../record/Table.vue"

const pinia = createTestingPinia({ createSpy: vi.fn, stubActions: false })
const recordStore = useRecordStore(pinia)
Expand Down
4 changes: 2 additions & 2 deletions src/components/Features/Table.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { useFeaturesStore, usePermissions, useRecordStore } from "@/stores/index

import record from './__fixtures__/record-with-features.json' assert { type: 'json' }
import Modal from "@/components/Modal.vue"
import DeleteFeatureModal from "@/components/Features/DeleteFeatureModal.vue"
import DeleteFeatureModal from "@/components/record/modals/DeleteFeatureModal.vue"
import EditForm from "@/components/Features/SingleItemOperatorForm.vue"
import TableComponent from "./Table.vue"
import TableComponent from "../record/Table.vue"

const pinia = createTestingPinia({ createSpy: vi.fn, stubActions: false })
const recordStore = useRecordStore(pinia)
Expand Down
2 changes: 1 addition & 1 deletion src/components/record/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ import { storeToRefs } from 'pinia'
import ParcellaireState from '@/components/record/State.vue'
import OperatorHistoryModal from '@/components/record/modals/HistoryModal.vue'
import FeaturesExportModal from '@/components/Features/ExportModal.vue'
import FeaturesExportModal from '@/components/record/modals/ExportModal.vue'
import DeleteParcellaireModal from '@/components/record/modals/DeleteParcelaireModal.vue'
import { useFeaturesStore, useOperatorStore, useRecordStore } from '@/stores/index.js'
Expand Down
Loading

0 comments on commit 190e177

Please sign in to comment.