feat: tag has a default and cannot be deselected, timeline allows picking a skill and vice-versa

This commit is contained in:
Adrien Marquès 2022-10-05 15:16:06 +02:00
parent 9b02041ca8
commit a027a47544
Signed by: xdrm-brackets
GPG Key ID: D75243CA236D825E
3 changed files with 61 additions and 25 deletions

View File

@ -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>

View File

@ -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!);
} }
protected onPick(id: tID, picked: boolean){ // selects or deselects a skill. If the skill is not in the current
if( picked ){ // select // folder, it navigates to the DEFAULT_TAG folder beforehand. Scrolls to
this.sel = id; // the selected skill when selected.
this.loadDetails(id); public select(id: tID, deselect: boolean) {
this.$emit('pick', id); const skill = skills.get(id);
return; if( deselect || skill == null ){
}
// deselect
this.sel = null; this.sel = null;
this.details = null; this.details = null;
this.$emit('pick', 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){
this.select(id, !picked);
} }
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);
} }
} }

View File

@ -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;