Merge branch '_sticky_nav' into 139_demandeur

This commit is contained in:
Mathieu Jaumotte 2021-05-23 11:51:38 +02:00
commit 3f2fe6a138
4 changed files with 238 additions and 3 deletions

View File

@ -37,12 +37,16 @@ const messages = {
ok: "OK",
cancel: "Annuler",
close: "Fermer",
next: "Suivant",
previous: "Précédent",
back: "Retour",
check_all: "cocher tout",
reset: "réinitialiser"
},
nav: {
next: "Suivant",
previous: "Précédent",
top: "Haut",
bottom: "Bas",
}
}
};

View File

@ -1,5 +1,6 @@
<template>
<banner></banner>
<sticky-nav></sticky-nav>
<h1 v-if="accompanyingCourse.step === 'DRAFT'">{{ $t('course.title.draft') }}</h1>
<h1 v-else>{{ $t('course.title.active') }}</h1>
@ -17,6 +18,7 @@
<script>
import { mapState } from 'vuex'
import Banner from './components/Banner.vue';
import StickyNav from './components/StickyNav.vue';
import PersonsAssociated from './components/PersonsAssociated.vue';
import Requestor from './components/Requestor.vue';
import SocialIssue from './components/SocialIssue.vue';
@ -29,6 +31,7 @@ export default {
name: 'App',
components: {
Banner,
StickyNav,
PersonsAssociated,
Requestor,
SocialIssue,
@ -68,7 +71,7 @@ export default {
}
a[name^="section"] {
position: absolute;
top: -2em;
top: -4em;
}
}
padding: 0.8em 0em;
@ -98,5 +101,6 @@ export default {
table {
}
}
}
</style>

View File

@ -0,0 +1,197 @@
<template>
<teleport to="#content_conainter .container.content .container">
<div id="navmap">
<nav>
<a href="#top">
<i class="fa fa-fw fa-square-o"></i>
<span>{{ $t('nav.top') }}</span>
</a>
<item
v-for="item of items"
:key="item.key"
:item="item"
:step="step">
</item>
<!--a href="#bottom">
<i class="fa fa-fw fa-square-o"></i>
<span>{{ $t('nav.bottom') }}</span>
</a-->
</nav>
</div>
</teleport>
</template>
<script>
import Item from './StickyNav/Item.vue';
export default {
name: "StickyNav",
components: {
Item
},
data() {
return {
header: document.querySelector("header.navigation.container"),
bannerName: document.querySelector("#header-accompanying_course-name"),
bannerDetails: document.querySelector("#header-accompanying_course-details"),
container: null,
sumBanner: null,
stickyNav: null,
limit: 25,
anchors: null,
items: [],
}
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
step() {
return this.accompanyingCourse.step;
},
top() {
return parseInt(window.getComputedStyle(this.stickyNav).getPropertyValue('top').slice(0, -2));
},
},
mounted() {
this.ready();
window.addEventListener('scroll', this.handleScroll);
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll);
},
methods: {
ready() {
// when mounted ready
this.container = document.querySelector("#content_conainter .container.content .container");
this.stickyNav = document.querySelector('#navmap');
this.sumBanner = this.header.offsetHeight + this.bannerName.offsetHeight + this.bannerDetails.offsetHeight;
this.anchorsMap();
const resizeObserver = new ResizeObserver(entries => {
// Listen to elements resize changes, then recalculate height sum and anchorsMap
// TODO only FF/Chrome!
this.sumBanner = this.header.offsetHeight + this.bannerName.offsetHeight + this.bannerDetails.offsetHeight;
//console.log('calculate sum', this.sumBanner);
this.items = [];
this.anchorsMap();
});
resizeObserver.observe(this.header);
resizeObserver.observe(this.bannerName);
resizeObserver.observe(this.bannerDetails);
resizeObserver.observe(this.container);
},
anchorsMap() {
this.anchors = document.querySelectorAll("h2 a[name^='section']");
this.anchors.forEach(anchor => {
//console.log('anchor', anchor);
this.items.push({
pos: this.findPosition(anchor)['y'],
active: false,
key: parseInt(anchor.name.slice(8).slice(0, -1)),
name: '#' + anchor.name
})
});
//console.log('items', this.items);
},
handleScroll(event) {
let pos = this.findPosition(this.stickyNav);
//console.log(window.scrollY);
//console.log('sum2', this.sumBanner);
let top = this.sumBanner + this.top - window.scrollY;
if (top > this.limit) {
//console.log('absolute', pos['y']);
this.stickyNav.style.position = 'absolute';
this.stickyNav.style.left = '-60px';
} else {
//console.log('fixed', pos['y']);
this.stickyNav.style.position = 'fixed';
this.stickyNav.style.left = pos['x'] + 'px';
}
this.switchActive();
},
findPosition(element) {
let posX = 0, posY = 0;
do {
posX += element.offsetLeft;
posY += element.offsetTop;
element = element.offsetParent;
}
while( element != null );
let pos = [];
pos['x'] = posX;
pos['y'] = posY;
return pos;
},
switchActive() {
this.items.forEach((item, i) => {
let next = (this.items[i+1]) ? this.items[i+1].pos : '1000000';
item.active =
(window.scrollY >= item.pos & window.scrollY < next) ? true : false;
}, this);
// last item never switch active because scroll reach bottom of page
if (document.body.scrollHeight == window.scrollY + window.innerHeight) {
this.items[this.items.length-1].active = true;
this.items[this.items.length-2].active = false;
} else {
this.items[this.items.length-1].active = false;
}
}
}
}
</script>
<style lang="scss">
div#navmap {
position: absolute;
top: 30px;
left: -60px; //-10%;
nav {
font-size: small;
a {
display: block;
box-sizing: border-box;
margin-bottom: -3px;
color: #71859669;
span {
display: none;
}
&:hover,
&.active {
span {
display: inline;
padding-left: 8px;
}
}
&:hover {
color: #718596b5;
}
&.active {
color: #df6a27; //#e2793d
}
}
}
}
@media only screen and (max-width: 768px) {
div.sticky-section {
display: none;
}
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<a
v-if="item.key <= 5"
:href="item.name"
:class="{ 'active': isActive }"
>
<i class="fa fa-fw fa-square"></i>
<span>{{ item.key }}</span>
</a>
<a
v-else-if="step === 'DRAFT'"
:href="item.name"
:class="{ 'active': isActive }"
>
<i class="fa fa-fw fa-square"></i>
<span>{{ item.key }}</span>
</a>
</template>
<script>
export default {
name: "Item",
props: ['item', 'step'],
computed: {
isActive() {
return this.item.active;
}
}
}
</script>