[Add] navbar scrollspy directive

Add navbar scrollspy
navbar style improvement
This commit is contained in:
Tony Yang 2021-01-27 22:53:58 +08:00
parent 5141a28a50
commit dd3708d493
Signed by: t510599
GPG Key ID: D88388851C28715D
4 changed files with 63 additions and 3 deletions

View File

@ -4,3 +4,4 @@ $pale-grey: #f0f7fd;
$dark-slate-blue: #1f4163; $dark-slate-blue: #1f4163;
$dark-sky-blue: #3d93e9; $dark-sky-blue: #3d93e9;
$slate-blue: #5f7a95; $slate-blue: #5f7a95;
$sky-blue: #9dc5ec;

View File

@ -369,10 +369,17 @@ $fontFamily: Noto Sans TC, monospace;
background: white; background: white;
z-index: 5; z-index: 5;
&-item { &-item {
margin: 5px 8px; margin: 0 8px;
padding: 5px 1em;
color: $mid-blue; color: $mid-blue;
font-family: $fontFamily; font-family: $fontFamily;
cursor: point; cursor: point;
border-right: 2px solid $sky-blue;
&.active {
font-weight: 900;
border-right: 2px solid $mid-blue;
}
} }
&-button { &-button {
color: $mid-blue; color: $mid-blue;

View File

@ -47,7 +47,7 @@
</div> </div>
</div> </div>
<nav v-if="navVisible"> <nav v-if="navVisible">
<div class="news-nav"> <div class="news-nav" v-scrollspy="{ selectors: navbarItems }">
<a class="news-nav-item" href="#schedule">重要時程</a> <a class="news-nav-item" href="#schedule">重要時程</a>
<a class="news-nav-item" href="#example">投稿主題範例</a> <a class="news-nav-item" href="#example">投稿主題範例</a>
<a class="news-nav-item" href="#code-of-conduct">Code of Conduct</a> <a class="news-nav-item" href="#code-of-conduct">Code of Conduct</a>
@ -69,6 +69,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'; import { Component, Prop, Vue } from 'vue-property-decorator';
import ScrollSpyDirective from './ScrollSpyDirective';
const DEAD_LINE = Math.floor( const DEAD_LINE = Math.floor(
new Date('22 Feb 2021 06:24:00 GMT+8').getTime() / 1000 new Date('22 Feb 2021 06:24:00 GMT+8').getTime() / 1000
@ -81,9 +82,23 @@ interface Countdown {
d: number; d: number;
} }
@Component @Component({
directives: {
scrollspy: ScrollSpyDirective
}
})
export default class CfpHeader extends Vue { export default class CfpHeader extends Vue {
private timerId!: number; private timerId!: number;
private navbarItems = [
'#schedule',
'#example',
'#code-of-conduct',
'#info-section',
'#process',
'#methods',
'#review',
'#precautions'
];
private navVisible = false; private navVisible = false;
private countdown: Countdown = { private countdown: Countdown = {
s: 0, s: 0,

View File

@ -0,0 +1,37 @@
import Vue, { DirectiveOptions, VNode, VNodeDirective } from 'vue';
let selectors!: string[];
let observer!: IntersectionObserver;
const ScrollSpyDirective: DirectiveOptions = {
bind (el: Element, binding: VNodeDirective , vnode: VNode) {
selectors = binding.value.selectors;
// highlight first element
el.querySelector(`[href="${location.hash || selectors[0] || ''}"]`)?.classList.toggle('active', true);
const config = {
rootMargin: '-10% 0px -80% 0px',
threshold: 0
};
observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
selectors.forEach((selector: string) => {
el.querySelector(`[href="${selector}"`)?.classList.toggle('active', selector === `#${entry.target.id}`);
});
}
});
}, config);
selectors.forEach((selector: string) => {
observer.observe(document.querySelector(selector) as Element);
});
},
unbind () {
observer.disconnect();
}
};
export default ScrollSpyDirective;