mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch '_sticky_nav' into 139_demandeur
This commit is contained in:
commit
3f2fe6a138
@ -37,12 +37,16 @@ const messages = {
|
|||||||
ok: "OK",
|
ok: "OK",
|
||||||
cancel: "Annuler",
|
cancel: "Annuler",
|
||||||
close: "Fermer",
|
close: "Fermer",
|
||||||
next: "Suivant",
|
|
||||||
previous: "Précédent",
|
|
||||||
back: "Retour",
|
back: "Retour",
|
||||||
check_all: "cocher tout",
|
check_all: "cocher tout",
|
||||||
reset: "réinitialiser"
|
reset: "réinitialiser"
|
||||||
},
|
},
|
||||||
|
nav: {
|
||||||
|
next: "Suivant",
|
||||||
|
previous: "Précédent",
|
||||||
|
top: "Haut",
|
||||||
|
bottom: "Bas",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<banner></banner>
|
<banner></banner>
|
||||||
|
<sticky-nav></sticky-nav>
|
||||||
|
|
||||||
<h1 v-if="accompanyingCourse.step === 'DRAFT'">{{ $t('course.title.draft') }}</h1>
|
<h1 v-if="accompanyingCourse.step === 'DRAFT'">{{ $t('course.title.draft') }}</h1>
|
||||||
<h1 v-else>{{ $t('course.title.active') }}</h1>
|
<h1 v-else>{{ $t('course.title.active') }}</h1>
|
||||||
@ -17,6 +18,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import Banner from './components/Banner.vue';
|
import Banner from './components/Banner.vue';
|
||||||
|
import StickyNav from './components/StickyNav.vue';
|
||||||
import PersonsAssociated from './components/PersonsAssociated.vue';
|
import PersonsAssociated from './components/PersonsAssociated.vue';
|
||||||
import Requestor from './components/Requestor.vue';
|
import Requestor from './components/Requestor.vue';
|
||||||
import SocialIssue from './components/SocialIssue.vue';
|
import SocialIssue from './components/SocialIssue.vue';
|
||||||
@ -29,6 +31,7 @@ export default {
|
|||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
Banner,
|
Banner,
|
||||||
|
StickyNav,
|
||||||
PersonsAssociated,
|
PersonsAssociated,
|
||||||
Requestor,
|
Requestor,
|
||||||
SocialIssue,
|
SocialIssue,
|
||||||
@ -68,7 +71,7 @@ export default {
|
|||||||
}
|
}
|
||||||
a[name^="section"] {
|
a[name^="section"] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -2em;
|
top: -4em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
padding: 0.8em 0em;
|
padding: 0.8em 0em;
|
||||||
@ -98,5 +101,6 @@ export default {
|
|||||||
table {
|
table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -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>
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user