feat: add smooth scrolling capabilities
This commit is contained in:
parent
c4a0587c8c
commit
f8f3b0e282
|
@ -19,7 +19,7 @@ import SkillPicker from './components/SkillPicker.vue';
|
|||
Home,
|
||||
Timeline,
|
||||
SkillPicker,
|
||||
},
|
||||
}
|
||||
})
|
||||
export default class App extends Vue {
|
||||
private selected: tID|null = null;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<h2>Featured in <b>{{ details.projects.length }}</b> {{ details.projects.length > 1 ? 'projects' : 'project' }}</h2>
|
||||
<h3>
|
||||
<template v-for='(proj) of details.projects'>
|
||||
<a :key='"pick-" + proj.name' :href='"#p-" + proj.name'>
|
||||
<a :key='"pick-" + proj.name' href @click='$event.preventDefault(); scroll(proj.name.replaceAll(" ", "_"));'>
|
||||
{{ proj.name }}
|
||||
</a>
|
||||
<span :key='proj.name'>, </span>
|
||||
|
@ -51,6 +51,7 @@
|
|||
import { Project } from '@/model/projects';
|
||||
import * as skills from '@/service/skills';
|
||||
import * as projects from '@/service/projects';
|
||||
import { go } from '@/service/scroller';
|
||||
|
||||
interface Details {
|
||||
icon: string|null;
|
||||
|
@ -87,6 +88,14 @@
|
|||
this.filterByTag();
|
||||
}
|
||||
|
||||
private scroll(proj_name: string) {
|
||||
const head = document.querySelector(`#search-header`) as HTMLElement;
|
||||
if( head == null ){
|
||||
return;
|
||||
}
|
||||
go(`project-${proj_name}`, -1.2*head.offsetHeight)
|
||||
}
|
||||
|
||||
// selects or deselects a skill. If the skill is not in the current
|
||||
// folder, it navigates to the DEFAULT_TAG folder beforehand. Scrolls to
|
||||
// the selected skill when selected.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<template class='project' v-for='(proj) of projects'>
|
||||
<!-- id is used for navigation -->
|
||||
<div :key="'start-'+proj.name" class='start' :id='"p-" + proj.name'>
|
||||
<div :key="'start-'+proj.name" class='start' :id='"project-" + proj.name.replaceAll(" ", "_")'>
|
||||
{{ proj.started_at | short_date }}
|
||||
</div>
|
||||
|
||||
|
@ -115,7 +115,7 @@
|
|||
return pluralize(diff/month, 'month');
|
||||
}
|
||||
return pluralize(diff/year, 'year');
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
export default class Timeline extends Vue {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
|
||||
let scroll_interval: number;
|
||||
|
||||
// scroll time in milliseconds
|
||||
const SCROLL_MS = 500;
|
||||
const SCROLL_MS_STEP = 5;
|
||||
|
||||
// go() scrolls to the element with the specified id with an optional offset.
|
||||
// It achieves a smooth scrolling compared to the direct default one.
|
||||
export function go(id: string, offset: number|undefined): void {
|
||||
// find item with id
|
||||
const item = document.querySelector(`#${id}`) as HTMLElement;
|
||||
if( item == null ){
|
||||
console.warn(`item with id '${id}' not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// get item absolute y coordinates
|
||||
let targety = absY(item, 0);
|
||||
if( offset != null ){
|
||||
targety += offset;
|
||||
}
|
||||
|
||||
clearInterval(scroll_interval);
|
||||
const step = (targety - document.body.scrollTop) / (SCROLL_MS / SCROLL_MS_STEP);
|
||||
scroll_interval = setInterval(
|
||||
() => smooth_scroll(targety, step),
|
||||
SCROLL_MS_STEP
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function absY(item: HTMLElement|null, children_y: number): number {
|
||||
if( item == null || item == document.body ){
|
||||
return children_y;
|
||||
}
|
||||
return absY(item.parentElement, children_y + item.offsetTop);
|
||||
}
|
||||
|
||||
// incremental smooth scroll
|
||||
function smooth_scroll(target: number, step: number) {
|
||||
const cur = document.body.scrollTop;
|
||||
const max = (document.body as any).scrollTopMax;
|
||||
|
||||
// moving up & reached top or target -> stop
|
||||
const upLimit = ( step < 0 && (cur <= 0 || cur <= target) );
|
||||
// moving down & reached bottom or target -> stop
|
||||
const downLimit = ( step > 0 && (cur >= max || cur >= target) );
|
||||
|
||||
if( upLimit || downLimit ){
|
||||
clearInterval(scroll_interval);
|
||||
document.body.scroll(0, target);
|
||||
return
|
||||
}
|
||||
|
||||
document.body.scroll(0, cur + step);
|
||||
}
|
Loading…
Reference in New Issue