feat: create the skill picker page
This commit is contained in:
parent
d6ab16026d
commit
d136b9d1e2
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<Home/>
|
<Home/>
|
||||||
|
<SkillPicker/>
|
||||||
<Timeline/>
|
<Timeline/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,11 +10,13 @@
|
||||||
import { Component, Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
import Home from './components/Home.vue';
|
import Home from './components/Home.vue';
|
||||||
import Timeline from './components/Timeline.vue';
|
import Timeline from './components/Timeline.vue';
|
||||||
|
import SkillPicker from './components/SkillPicker.vue';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
Home,
|
Home,
|
||||||
Timeline,
|
Timeline,
|
||||||
|
SkillPicker,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class App extends Vue {
|
export default class App extends Vue {
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
width: $width;
|
width: $width;
|
||||||
height: $height;
|
height: $height;
|
||||||
|
|
||||||
background: #07142d;
|
background: #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes wave-x {
|
@keyframes wave-x {
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
<template>
|
||||||
|
<div id='skill-picker'>
|
||||||
|
|
||||||
|
<div class='container'>
|
||||||
|
|
||||||
|
<section class='categories'>
|
||||||
|
<SkillCard v-for='(t) of tags'
|
||||||
|
:key='t'
|
||||||
|
:id='t'
|
||||||
|
:active='t == tag'
|
||||||
|
folder='1'
|
||||||
|
width='18rem'
|
||||||
|
@pick='onTag(t, $event)'/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class='skills'>
|
||||||
|
<SkillCard v-for='(id) of ids'
|
||||||
|
:key='id'
|
||||||
|
v-show='hide.indexOf(id) < 0'
|
||||||
|
:id='id'
|
||||||
|
:active='id == sel'
|
||||||
|
width='18rem'
|
||||||
|
@pick='onPick(id, $event)' />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button v-show='this.sel != null'>Browse projects</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
import SkillCard from './SkillCard.vue';
|
||||||
|
import { tID, Skills } from '@/model/skills';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
SkillCard,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class SkillPicker extends Vue {
|
||||||
|
// list of available skills
|
||||||
|
readonly ids: string[] = Object.keys(Skills);
|
||||||
|
// currently selected skill
|
||||||
|
private sel: string|null = tID.Vue.toString();
|
||||||
|
|
||||||
|
// list of ids to hide according to the current tag
|
||||||
|
private hide: string[] = [];
|
||||||
|
|
||||||
|
// available categories (tags)
|
||||||
|
private tags: string[] = [];
|
||||||
|
// currently selected tag
|
||||||
|
private tag: string|null = "web";
|
||||||
|
|
||||||
|
private mounted() {
|
||||||
|
this.tags = this.fetchTags();
|
||||||
|
this.filterByTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetchTags(): string[] {
|
||||||
|
const tags: string[] = [];
|
||||||
|
|
||||||
|
for( const sid of this.ids ){
|
||||||
|
const id = parseInt(sid) as tID;
|
||||||
|
const skill = Skills[id];
|
||||||
|
if( skill == undefined ){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for( const tag of skill.tags ){
|
||||||
|
if( tags.indexOf(tag) < 0 ){
|
||||||
|
tags.push(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private onPick(id: string, picked: boolean){
|
||||||
|
if( picked ){ // select
|
||||||
|
this.sel = id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( !picked && id == this.sel ){ // deselect
|
||||||
|
this.sel = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private onTag(t: string, picked: boolean){
|
||||||
|
if( picked ){ // select
|
||||||
|
this.tag = t;
|
||||||
|
this.filterByTag();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( !picked && t == this.tag ){ // deselect
|
||||||
|
this.tag = null;
|
||||||
|
this.filterByTag();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply filter by tag
|
||||||
|
private filterByTag(){
|
||||||
|
const tag = this.tag;
|
||||||
|
|
||||||
|
// no folder selected -> hide everything
|
||||||
|
if( tag == null || this.tags.indexOf(tag) < 0 ){
|
||||||
|
this.tag = null;
|
||||||
|
this.hide = this.ids;
|
||||||
|
|
||||||
|
// deselect if selection has been filtered out
|
||||||
|
if( this.sel != null && this.hide.indexOf(this.sel) >= 0 ){
|
||||||
|
this.sel = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear filter
|
||||||
|
this.hide = [];
|
||||||
|
|
||||||
|
for( const sid of this.ids ){
|
||||||
|
const id = parseInt(sid) as tID;
|
||||||
|
const skill = Skills[id];
|
||||||
|
if( skill == undefined ){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if( skill.tags.indexOf(tag) < 0 ){
|
||||||
|
this.hide.push(sid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// deselect if selection has been filtered out
|
||||||
|
if( this.sel != null && this.hide.indexOf(this.sel) >= 0 ){
|
||||||
|
this.sel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
$page-margin: 3rem;
|
||||||
|
|
||||||
|
#skill-picker {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
background: linear-gradient(45deg, #564ba4, #745cfc);
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
width: calc( 100vw - #{2*$page-margin} );
|
||||||
|
height: calc( 100vh - #{2*$page-margin} );
|
||||||
|
margin: $page-margin;
|
||||||
|
|
||||||
|
background: #202228;
|
||||||
|
|
||||||
|
border-radius: 1em / 1em;
|
||||||
|
|
||||||
|
padding: 2em;
|
||||||
|
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 20em;
|
||||||
|
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: visible;
|
||||||
|
|
||||||
|
.skill-card {
|
||||||
|
margin: .3em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.skills {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 20em;
|
||||||
|
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: visible;
|
||||||
|
|
||||||
|
.skill-card {
|
||||||
|
margin: .3em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: calc( 100% - #{$page-margin} );
|
||||||
|
left: 50%;
|
||||||
|
|
||||||
|
padding: .6em 2em;
|
||||||
|
|
||||||
|
color: #202228;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 600;
|
||||||
|
background: #fff;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
border-radius: 2em;
|
||||||
|
|
||||||
|
box-shadow: 0 0 .5em transparent;
|
||||||
|
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
transition: box-shadow .2s ease-in-out,
|
||||||
|
transform .2s ease-in-out,
|
||||||
|
color .2s ease-in-out;
|
||||||
|
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #000;
|
||||||
|
box-shadow: 0 0 .3em #191b1f;
|
||||||
|
transform: translateX(-50%) translateY(-50%) scale(1.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -121,6 +121,7 @@
|
||||||
|
|
||||||
$icon-width: 2.3rem;
|
$icon-width: 2.3rem;
|
||||||
$space-width: 1rem;
|
$space-width: 1rem;
|
||||||
|
$bg-color: #202228;
|
||||||
|
|
||||||
#timeline {
|
#timeline {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
@ -134,7 +135,7 @@
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #161619;
|
background: $bg-color;
|
||||||
|
|
||||||
padding: 0 5rem;
|
padding: 0 5rem;
|
||||||
|
|
||||||
|
@ -157,7 +158,7 @@
|
||||||
height: #{$icon-width + .3rem};
|
height: #{$icon-width + .3rem};
|
||||||
margin-top: .3rem;
|
margin-top: .3rem;
|
||||||
|
|
||||||
background: #161619;
|
background: $bg-color;
|
||||||
}
|
}
|
||||||
.src-icon, .doc-icon, .end-icon {
|
.src-icon, .doc-icon, .end-icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -166,7 +167,7 @@
|
||||||
height: #{$icon-width + .1rem};
|
height: #{$icon-width + .1rem};
|
||||||
margin-top: .1rem;
|
margin-top: .1rem;
|
||||||
|
|
||||||
background: #161619;
|
background: $bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.start {
|
.start {
|
||||||
|
@ -183,7 +184,7 @@
|
||||||
|
|
||||||
padding-top: -.2rem;
|
padding-top: -.2rem;
|
||||||
|
|
||||||
background: #161619;
|
background: $bg-color;
|
||||||
}
|
}
|
||||||
.name, .end {
|
.name, .end {
|
||||||
b {
|
b {
|
||||||
|
@ -232,7 +233,7 @@
|
||||||
margin-bottom: .4em;
|
margin-bottom: .4em;
|
||||||
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #28282d;
|
background: #34343b;
|
||||||
|
|
||||||
border-radius: .4em / .4em;
|
border-radius: .4em / .4em;
|
||||||
|
|
||||||
|
@ -251,9 +252,9 @@
|
||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
margin-bottom: 1.5em;
|
margin-bottom: 1.5em;
|
||||||
|
|
||||||
background: #28282d;
|
background: #34343b;
|
||||||
|
|
||||||
border: .1rem solid #2f2f33;
|
border: .1rem solid #45454b;
|
||||||
border-radius: .4em / .4em;
|
border-radius: .4em / .4em;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|
||||||
|
@ -269,8 +270,8 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
background: #202024;
|
background: darken(#34343b, 4%);
|
||||||
border: .1rem solid #2f2f33;
|
border: .1rem solid darken(#45454b, 4%);
|
||||||
border-radius: .4em / .4em;
|
border-radius: .4em / .4em;
|
||||||
|
|
||||||
transform: translateZ(-1px);
|
transform: translateZ(-1px);
|
||||||
|
|
Loading…
Reference in New Issue