Skip to content

Commit

Permalink
Rend sticky les onglets de l'audit
Browse files Browse the repository at this point in the history
* base structure of AraTabs

add panels to component

style tabs a bit

focus selected tab when using arrows

adjust tabs style

make tabs scrollable

add notes tab

fix tabs focus style

fix auditStepThree

make tab panels focusable

add Home/End shortcuts on tabs

fix page title when changin tab

remove tabs padding and update finished audit wording

sync the tabs top property with the size of the sticky indicator

sdmlkfj

show left side border only on scroll

adjust header actions

* fix rebase artifacts

* fix some pr feedback

* only show bottom border when touching filters

* adjust thematic anchors scroll margin

* fix border appearing too soon on small viewports

* update changelog
  • Loading branch information
hissalht authored Dec 8, 2023
1 parent 86f0e63 commit e4b266c
Show file tree
Hide file tree
Showing 15 changed files with 1,428 additions and 847 deletions.
24 changes: 12 additions & 12 deletions confiture-web-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"marked": "^4.2.4",
"pinia": "^2.0.28",
"slugify": "^1.6.5",
"vue": "^3.2.45",
"vue": "^3.3.8",
"vue-matomo": "^4.2.0",
"vue-router": "^4.2.5"
},
Expand All @@ -34,16 +34,16 @@
"@types/lodash-es": "^4.17.6",
"@types/marked": "^4.0.8",
"@types/node": "^18.11.15",
"@typescript-eslint/eslint-plugin": "^5.46.1",
"@typescript-eslint/parser": "^5.46.1",
"@vitejs/plugin-vue": "^4.0.0",
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.8.0",
"prettier": "^2.8.1",
"typescript": "^4.9.4",
"vite": "^4.0.1",
"vue-tsc": "^1.0.13"
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@vitejs/plugin-vue": "^4.4.1",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-vue": "^9.18.1",
"prettier": "^3.0.3",
"typescript": "^5.2.2",
"vite": "^4.5.0",
"vue-tsc": "^1.8.22"
}
}
10 changes: 10 additions & 0 deletions confiture-web-app/src/assets/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

Tous les changements notables de Ara sont documentés ici avec leur date, leur catégorie (nouvelle fonctionnalité, correction de bug ou autre changement) et leur pull request (PR) associée.

## 08/12/2023

### Nouvelles fonctionnalités 🚀

- Les onglets de page sur la page d'audit sont maintenant collés au haut de l'écran ([#541](https://github.com/DISIC/Ara/pull/541))

### Autres changements ⚙️

- Ajuste le layout de la barre d'actions sur la page d'audit ([#541](https://github.com/DISIC/Ara/pull/541))

## 06/12/2023

### Corrections 🐛
Expand Down
231 changes: 231 additions & 0 deletions confiture-web-app/src/components/AraTabs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
<!--
This component is only used to replicate DSFR tabs with sticky functionality.
For tabs that have no sticky needs, please use `fr-tabs` instead of this component.
https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/onglet
-->

<script setup lang="ts" generic="T">
import { onMounted, ref, watch } from "vue";
import { useUniqueId } from "../composables/useUniqueId";
import { waitForElement } from "../utils";
const props = defineProps<{
tabs: { label: string; data: T; icon?: string }[];
}>();
defineSlots<{
panel(props: { i: number; data: T }): void;
}>();
const emit = defineEmits<{
(e: "change", currentTab: number): void;
}>();
const uniqueId = useUniqueId();
const tabId = (i: number) => "tab-" + uniqueId.value + "-" + i;
const panelId = (i: number) => "panel-" + uniqueId.value + "-" + i;
const currentTab = ref(0);
const tabControlRefs = ref<HTMLButtonElement[]>();
const selectNextTab = () => {
currentTab.value = (currentTab.value + 1) % props.tabs.length;
tabControlRefs.value?.at(currentTab.value)?.focus();
};
const selectPreviousTab = () => {
if (currentTab.value === 0) {
currentTab.value = props.tabs.length - 1;
} else {
currentTab.value -= 1;
}
tabControlRefs.value?.at(currentTab.value)?.focus();
};
const selectFirstTab = () => {
currentTab.value = 0;
tabControlRefs.value?.at(currentTab.value)?.focus();
};
const selectLastTab = () => {
currentTab.value = props.tabs.length - 1;
tabControlRefs.value?.at(currentTab.value)?.focus();
};
watch(currentTab, (currentTab) => {
emit("change", currentTab);
});
// Observe the height of the sticky indicator and sync the `top` CSS property with it.
const tabsTopOffset = ref("0");
onMounted(async () => {
const el = await waitForElement("#sticky-indicator");
const resizeObserver = new ResizeObserver((entries) => {
tabsTopOffset.value = entries[0].target.clientHeight + "px";
});
resizeObserver.observe(el);
});
</script>

<!--
TODO:
- ajouter une shadow quand les onglets sont scrollables
-->

<template>
<div class="tabs-wrapper" :style="{ '--tabs-top-offset': tabsTopOffset }">
<ul role="tablist" class="tabs">
<li v-for="(tab, i) in tabs" :key="i">
<button
:id="tabId(i)"
ref="tabControlRefs"
role="tab"
:aria-controls="panelId(i)"
:aria-selected="i === currentTab ? 'true' : 'false'"
:tabindex="i === currentTab ? undefined : '-1'"
:class="{
'fr-tabs__tab--icon-left': !!tab.icon,
...(!!tab.icon && {
[`fr-icon-${tab.icon}`]: !!tab.icon,
}),
}"
@keydown.right.prevent="selectNextTab"
@click="currentTab = i"
@keydown.down.prevent="selectNextTab"
@keydown.left.prevent="selectPreviousTab"
@keydown.up.prevent="selectPreviousTab"
@keydown.home.prevent="selectFirstTab"
@keydown.end.prevent="selectLastTab"
>
{{ tab.label }}
</button>
</li>
</ul>
</div>
<div class="panel-container">
<template v-for="(tab, i) in tabs" :key="i">
<div
:id="panelId(i)"
:aria-labelledby="tabId(i)"
:class="{ visible: i === currentTab }"
role="tabpanel"
tabindex="0"
>
<slot v-if="i === currentTab" name="panel" :data="tab.data" :i="i" />
</div>
</template>
</div>
</template>

<style scoped>
/* The styles are mostly copy-pasted from the DSFR tabs component. */
.tabs-wrapper {
background-color: var(--background-default-grey);
z-index: 1;
position: sticky;
top: var(--tabs-top-offset, 4rem);
}
.tabs-wrapper::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px;
background-color: var(--border-default-grey);
}
.tabs {
margin: 0;
display: flex;
gap: 0.25rem;
list-style: none;
padding: 0;
overflow-x: auto;
}
li {
padding: 0;
}
.tabs button {
--text-spacing: 0;
--title-spacing: 0;
--underline-img: none;
--hover-tint: var(--hover);
align-items: center;
display: inline-flex;
flex-direction: row;
font-size: 1rem;
font-weight: 700;
height: 100%;
line-height: 1.5rem;
min-height: 2.5rem;
overflow: visible;
padding: 0.5rem 1rem;
position: relative;
white-space: nowrap;
width: -moz-fit-content;
width: fit-content;
z-index: 1;
}
.tabs button:hover {
background-color: var(--hover-tint);
}
.tabs button:active {
background-color: var(--active-tint);
}
.tabs button:focus {
outline: 2px solid var(--dsfr-outline);
outline-offset: -2px;
}
[aria-selected="true"] {
--idle: transparent;
--hover: var(--background-default-grey-hover);
--active: var(--background-default-grey-active);
background-color: var(--background-default-grey);
color: var(--text-active-blue-france);
border: 1px solid var(--border-default-grey);
border-bottom-color: transparent;
position: relative;
}
[aria-selected="true"]::after {
content: "";
left: -1px;
top: -1px;
right: -1px;
height: 2px;
background-color: var(--text-active-blue-france);
position: absolute;
z-index: 1;
}
[aria-selected="false"] {
--idle: transparent;
--hover: var(--background-action-low-blue-france-hover);
--active: var(--background-action-low-blue-france-active);
background-color: var(--background-action-low-blue-france);
color: var(--text-action-high-grey);
border: 1px solid transparent;
border-bottom-color: var(--border-default-grey);
}
[role="tabpanel"]:not(.visible) {
display: none;
}
.panel-container {
border: 1px solid var(--border-default-grey);
border-top: none;
padding: 2rem;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ const pages = ref(
{ name: "Plan du site", url: "" },
{ name: "Aide", url: "" },
{ name: "Authentification", url: "" },
]
],
);
const procedureAuditorName = ref(
props.defaultValues?.auditorName ?? accountStore.account?.name ?? ""
props.defaultValues?.auditorName ?? accountStore.account?.name ?? "",
);
const procedureAuditorEmail = ref(
props.defaultValues?.auditorEmail ?? accountStore.account?.email ?? ""
props.defaultValues?.auditorEmail ?? accountStore.account?.email ?? "",
);
const pageNameFieldRefs = ref<InstanceType<typeof DsfrField>[]>([]);
Expand Down
18 changes: 9 additions & 9 deletions confiture-web-app/src/components/AuditGenerationFilters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const auditStore = useAuditStore();
const resultsCount = computed(() =>
filterStore.filteredTopics
.map((t) => t.criteria.length)
.reduce((total, length) => (total += length), 0)
.reduce((total, length) => (total += length), 0),
);
const search = ref("");
Expand Down Expand Up @@ -65,26 +65,26 @@ async function displayFilters() {
watch(
() => filterStore.hideEvaluatedCriteria,
() => filterStore.updateEvaluatedCriteria()
() => filterStore.updateEvaluatedCriteria(),
);
const compliantCount = computed(
() =>
resultStore.allResults?.filter(
(r) => r.status === CriteriumResultStatus.COMPLIANT
).length
(r) => r.status === CriteriumResultStatus.COMPLIANT,
).length,
);
const notCompliantCount = computed(
() =>
resultStore.allResults?.filter(
(r) => r.status === CriteriumResultStatus.NOT_COMPLIANT
).length
(r) => r.status === CriteriumResultStatus.NOT_COMPLIANT,
).length,
);
const notApplicableCount = computed(
() =>
resultStore.allResults?.filter(
(r) => r.status === CriteriumResultStatus.NOT_APPLICABLE
).length
(r) => r.status === CriteriumResultStatus.NOT_APPLICABLE,
).length,
);
</script>

Expand All @@ -93,7 +93,7 @@ const notApplicableCount = computed(
v-if="!showFilters"
ref="displayFiltersRef"
type="button"
class="fr-btn fr-btn--sm fr-btn--tertiary fr-icon-arrow-right-s-line-double toggle-column-button"
class="fr-btn fr-btn--sm fr-btn--tertiary fr-icon-arrow-right-s-line-double toggle-column-button fr-mr-3v"
@click="displayFilters"
>
<span class="sr-only">Afficher la colonne des filtres</span>
Expand Down
Loading

0 comments on commit e4b266c

Please sign in to comment.