feat: tag has a default and cannot be deselected, timeline allows picking a skill and vice-versa
This commit is contained in:
parent
9b02041ca8
commit
a027a47544
23
src/App.vue
23
src/App.vue
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<Home/>
|
<Home/>
|
||||||
<SkillPicker @pick='onPick($event)'/>
|
<SkillPicker ref='picker' @pick='onPick($event)'/>
|
||||||
<Timeline ref='timeline'/>
|
<Timeline ref='timeline' @pick='onPicked($event)'/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -24,6 +24,15 @@ import SkillPicker from './components/SkillPicker.vue';
|
||||||
export default class App extends Vue {
|
export default class App extends Vue {
|
||||||
private selected: tID|null = null;
|
private selected: tID|null = null;
|
||||||
|
|
||||||
|
private mounted() {
|
||||||
|
const picker = this.$refs.picker as SkillPicker;
|
||||||
|
if( picker == null ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
picker.select(tID.Vue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// skill picker selection -> filters the timeline
|
||||||
protected onPick(id: tID|null) {
|
protected onPick(id: tID|null) {
|
||||||
const timeline = this.$refs.timeline as Timeline;
|
const timeline = this.$refs.timeline as Timeline;
|
||||||
if( timeline == null ){
|
if( timeline == null ){
|
||||||
|
@ -31,6 +40,16 @@ export default class App extends Vue {
|
||||||
}
|
}
|
||||||
timeline.filter(id);
|
timeline.filter(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skill picked from the timeline -> select on the skill picker
|
||||||
|
protected onPicked(id: tID) {
|
||||||
|
const picker = this.$refs.picker as SkillPicker;
|
||||||
|
if( picker == null ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
picker.select(id, false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,8 @@
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_TAG = "all";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
SkillCard,
|
SkillCard,
|
||||||
|
@ -74,29 +76,42 @@
|
||||||
private filtered: tID[] = [];
|
private filtered: tID[] = [];
|
||||||
|
|
||||||
// available categories (tags)
|
// available categories (tags)
|
||||||
private tags: string[] = skills.tags();
|
private tags: string[] = [DEFAULT_TAG, ...skills.tags()];
|
||||||
// currently selected tag
|
// currently selected tag
|
||||||
private tag: string|null = "web";
|
private tag: string = "web";
|
||||||
|
|
||||||
// details section when a skill is selected
|
// details section when a skill is selected
|
||||||
private details: Details|null = null;
|
private details: Details|null = null;
|
||||||
|
|
||||||
private mounted() {
|
private mounted() {
|
||||||
this.filterByTag();
|
this.filterByTag();
|
||||||
this.loadDetails(this.sel!);
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
public select(id: tID, deselect: boolean) {
|
||||||
|
const skill = skills.get(id);
|
||||||
|
if( deselect || skill == null ){
|
||||||
|
this.sel = null;
|
||||||
|
this.details = null;
|
||||||
|
this.$emit('pick', null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not available in current tag filter (folder)
|
||||||
|
// -> navigate to default tag
|
||||||
|
if( skill.tags.indexOf(this.tag) < 0 ){
|
||||||
|
this.onTag(DEFAULT_TAG, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sel = id;
|
||||||
|
this.loadDetails(id);
|
||||||
|
this.$emit('pick', id);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onPick(id: tID, picked: boolean){
|
protected onPick(id: tID, picked: boolean){
|
||||||
if( picked ){ // select
|
this.select(id, !picked);
|
||||||
this.sel = id;
|
|
||||||
this.loadDetails(id);
|
|
||||||
this.$emit('pick', id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// deselect
|
|
||||||
this.sel = null;
|
|
||||||
this.details = null;
|
|
||||||
this.$emit('pick', null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onTag(t: string, picked: boolean){
|
protected onTag(t: string, picked: boolean){
|
||||||
|
@ -105,8 +120,8 @@
|
||||||
this.filterByTag();
|
this.filterByTag();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( !picked && t == this.tag ){ // deselect
|
if( !picked && t == this.tag ){ // back to default
|
||||||
this.tag = null;
|
this.tag = DEFAULT_TAG;
|
||||||
this.filterByTag();
|
this.filterByTag();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -114,17 +129,17 @@
|
||||||
|
|
||||||
// apply filter by tag
|
// apply filter by tag
|
||||||
private filterByTag(){
|
private filterByTag(){
|
||||||
const tag = this.tag;
|
if( this.tag == DEFAULT_TAG ){
|
||||||
if( tag == null ){
|
this.filtered = this.ids;
|
||||||
this.tag = null;
|
|
||||||
this.filtered = [];
|
|
||||||
} else {
|
} else {
|
||||||
this.filtered = skills.filtered(tag);
|
this.filtered = skills.filtered(this.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deselect if selection has been filtered out
|
// maintain selection behavior:
|
||||||
|
// - deselect if current is no more present
|
||||||
|
// - keep if still listed
|
||||||
if( this.sel != null && this.filtered.indexOf(this.sel) < 0 ){
|
if( this.sel != null && this.filtered.indexOf(this.sel) < 0 ){
|
||||||
this.sel = null;
|
this.select(0, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
<img :key="'skill-icon-'+proj.name" class='skill-icon' src='../assets/timeline/skills.svg' />
|
<img :key="'skill-icon-'+proj.name" class='skill-icon' src='../assets/timeline/skills.svg' />
|
||||||
<div :key="'skillset-'+proj.name" class='skillset'>
|
<div :key="'skillset-'+proj.name" class='skillset'>
|
||||||
<SkillCard v-for='(id) of proj.skills' :key='id' :id='id'/>
|
<SkillCard v-for='(id) of proj.skills' :key='"timeline-" + proj.name + "-" + id' :id='id' :active='id == skill' @pick='$emit("pick", id)'/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img :key="'desc-icon-'+proj.name" class='desc-icon' src='../assets/timeline/info.svg' />
|
<img :key="'desc-icon-'+proj.name" class='desc-icon' src='../assets/timeline/info.svg' />
|
||||||
|
@ -119,6 +119,7 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
export default class Timeline extends Vue {
|
export default class Timeline extends Vue {
|
||||||
|
private skill: tID|null = null;
|
||||||
private projects: Project[] = [];
|
private projects: Project[] = [];
|
||||||
|
|
||||||
private mounted() {
|
private mounted() {
|
||||||
|
@ -147,6 +148,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public filter(skill: tID|null) {
|
public filter(skill: tID|null) {
|
||||||
|
this.skill = skill;
|
||||||
if( skill == null ){
|
if( skill == null ){
|
||||||
this.projects = [];
|
this.projects = [];
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue