Compare commits

..

6 Commits

8 changed files with 355 additions and 169 deletions

View File

@ -9,7 +9,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'; import { Component, Prop, Vue } from 'vue-property-decorator';
import { tID } from '@/model/skills'; import { skillLabel, tID } from '@/model/skills';
import * as skills from '@/service/skills'; import * as skills from '@/service/skills';
@Component({}) @Component({})
@ -59,7 +59,7 @@ export default class SkillCard extends Vue {
if ( skill == null ) { if ( skill == null ) {
return ''; return '';
} }
return skill.name; return this.$t(skillLabel(this.id)).toString();
} }
private onClick(e: MouseEvent) { private onClick(e: MouseEvent) {

View File

@ -8,7 +8,7 @@
<SkillCard v-for='(t) of tags' <SkillCard v-for='(t) of tags'
:key='t' :key='t'
:active='t == tag' :active='t == tag'
:folder='t' :folder='$t(tagLabel(t))'
@pick='onTag(t, $event)'/> @pick='onTag(t, $event)'/>
</section> </section>
@ -49,7 +49,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator'; import { Component, Vue } from 'vue-property-decorator';
import SkillCard from './SkillCard.vue'; import SkillCard from './SkillCard.vue';
import { tID } from '@/model/skills'; import { skillLabel, tagLabel, tID, tTag } from '@/model/skills';
import { Project } from '@/model/projects'; import { Project } from '@/model/projects';
import * as skills from '@/service/skills'; import * as skills from '@/service/skills';
import * as projects from '@/service/projects'; import * as projects from '@/service/projects';
@ -62,7 +62,7 @@ interface Details {
text: string; text: string;
} }
const DEFAULT_TAG = 'all'; const DEFAULT_TAG = tTag.All;
@Component({ @Component({
components: { components: {
@ -79,13 +79,18 @@ export default class SkillPicker extends Vue {
private filtered: tID[] = []; private filtered: tID[] = [];
// available categories (tags) // available categories (tags)
private tags: string[] = [DEFAULT_TAG, ...skills.tags()]; private tags: tTag[] = [DEFAULT_TAG, ...skills.tags()];
// currently selected tag // currently selected tag
private tag: string = 'web'; private tag: tTag = tTag.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;
// returns the label for a tag
protected tagLabel(t: tTag): string {
return tagLabel(t);
}
// selects or deselects a skill. If the skill is not in the current // selects or deselects a skill. If the skill is not in the current
// folder, it navigates to the DEFAULT_TAG folder beforehand. Scrolls to // folder, it navigates to the DEFAULT_TAG folder beforehand. Scrolls to
// the selected skill when selected. // the selected skill when selected.
@ -113,17 +118,12 @@ export default class SkillPicker extends Vue {
this.select(id, !picked); this.select(id, !picked);
} }
protected onTag(t: string, picked: boolean) { protected onTag(t: tTag, picked: boolean) {
if ( picked ) { // select if ( picked ) { // select
this.tag = t; this.tag = t;
this.filterByTag(); this.filterByTag();
return; return;
} }
if ( !picked && t == this.tag ) { // back to default
this.tag = DEFAULT_TAG;
this.filterByTag();
return;
}
} }
protected browse() { protected browse() {

View File

@ -21,7 +21,7 @@
<img src='../assets/timeline/project.svg' /> <img src='../assets/timeline/project.svg' />
</div> </div>
<div :key="'name-'+proj.name" class='name'> <div :key="'name-'+proj.name" class='name'>
Created <b>{{ proj.name }}</b> <span>{{ proj.started_at | date_diff }} ago</span> {{ $t('project.created') }} <b>{{ proj.name }}</b> <span>{{ elapsed(proj.started_at) }}</span>
</div> </div>
<div :key="'joint-start-'+proj.name" class='joint-start' /> <div :key="'joint-start-'+proj.name" class='joint-start' />
@ -36,14 +36,14 @@
<div :key="'desc-icon-'+proj.name" class='desc-icon'> <div :key="'desc-icon-'+proj.name" class='desc-icon'>
<img src='../assets/timeline/info.svg' /> <img src='../assets/timeline/info.svg' />
</div> </div>
<div :key="'desc-'+proj.name" class='desc' v-html='proj.info'></div> <div :key="'desc-'+proj.name" class='desc' v-html='proj.info[$i18n.locale]'></div>
<template v-if='proj.source != null'> <template v-if='proj.source != null'>
<div :key="'src-icon-'+proj.name" class='src-icon'> <div :key="'src-icon-'+proj.name" class='src-icon'>
<img src='../assets/timeline/src.svg' /> <img src='../assets/timeline/src.svg' />
</div> </div>
<div :key="'src-'+proj.name" class='src' > <div :key="'src-'+proj.name" class='src' >
Hosted at <a :href='proj.source.link'>{{ proj.source.name }}</a> <span>({{ proj.commits }} commits)</span> {{ $t('project.sources') }} <a :href='proj.source.link'>{{ proj.source.name }}</a> <span>({{ proj.commits }} commits)</span>
</div> </div>
</template> </template>
@ -52,7 +52,7 @@
<img src='../assets/timeline/doc.svg' /> <img src='../assets/timeline/doc.svg' />
</div> </div>
<div :key="'doc-'+proj.name" class='doc'> <div :key="'doc-'+proj.name" class='doc'>
Documentation at <a :href='proj.doc.link'>{{ proj.doc.name }}</a> {{ $t('project.doc') }} <a :href='proj.doc.link'>{{ proj.doc.name }}</a>
</div> </div>
</template> </template>
@ -61,10 +61,10 @@
</div> </div>
<div :key="'end-'+proj.name" class='end'> <div :key="'end-'+proj.name" class='end'>
<template v-if='proj.stopped_at != null'> <template v-if='proj.stopped_at != null'>
Project stopped in {{ proj.stopped_at | short_date }} <span>{{ proj.stopped_at | date_diff }} ago</span> {{ $t('project.end') }} {{ proj.stopped_at | short_date }} <span>{{ elapsed(proj.stopped_at) }}</span>
</template> </template>
<template v-else> <template v-else>
Project still active {{ $t('project.still') }}
</template> </template>
</div> </div>
@ -84,34 +84,15 @@ import { tID } from '../model/skills';
import * as projects from '../service/projects'; import * as projects from '../service/projects';
import * as scroller from '../service/scroller'; import * as scroller from '../service/scroller';
function pluralize(n: number, s: string): string { interface TimeDiff {
n = Math.floor(Math.abs(n)); diff: number;
const plural = (n > 1); one: string; // singular translation label
plural: string; // plural translation label
switch (s) {
case 'second':
return plural ? `${n} seconds` : `1 second`;
case 'minute':
return plural ? `${n} minutes` : `1 minute`;
case 'day':
return plural ? `${n} days` : `1 day`;
case 'month':
return plural ? `${n} months` : `1 month`;
case 'year':
return plural ? `${n} years` : `1 year`;
}
return '';
} }
@Component({ // returns a TimeDiff from a date. Holds the time elapsed until now in the most
components: { // broad unit that is greater than 0.
SkillCard, function getTimeDiff(date: Date): TimeDiff {
},
filters: {
short_date(date: Date): string {
return date.toLocaleDateString('en-US', { month: 'short', year: 'numeric' });
},
date_diff(date: Date): string {
const minute = 60 * 1000; const minute = 60 * 1000;
const hour = 60 * minute; const hour = 60 * minute;
const day = 24 * hour; const day = 24 * hour;
@ -122,25 +103,34 @@ function pluralize(n: number, s: string): string {
const diff = now.getTime() - date.getTime(); const diff = now.getTime() - date.getTime();
if ( diff < 0 ) { if ( diff < 0 ) {
return 'sometime'; return {diff: 0, one: 'time.some', plural: 'time.some'};
} }
if ( diff < minute ) { if ( diff < minute ) {
return pluralize(diff, 'second'); return {diff: diff, one: 'time.second', plural: 'time.seconds'};
} }
if ( diff < hour ) { if ( diff < hour ) {
return pluralize(diff / minute, 'minute'); return {diff: diff / minute, one: 'time.minute', plural: 'time.minutes'};
} }
if ( diff < day ) { if ( diff < day ) {
return pluralize(diff / hour, 'hour'); return {diff: diff / hour, one: 'time.hour', plural: 'time.hours'};
} }
if ( diff < month ) { if ( diff < month ) {
return pluralize(diff / day, 'day'); return {diff: diff / day, one: 'time.day', plural: 'time.days'};
} }
if ( diff < year ) { if ( diff < year ) {
return pluralize(diff / month, 'month'); return {diff: diff / month, one: 'time.month', plural: 'time.months'};
} }
return pluralize(diff / year, 'year'); return {diff: diff / year, one: 'time.year', plural: 'time.years'};
}
@Component({
components: {
SkillCard,
},
filters: {
short_date(date: Date): string {
return date.toLocaleDateString(navigator.language, { month: 'short', year: 'numeric' });
}, },
}, },
}) })
@ -161,6 +151,23 @@ export default class Timeline extends Vue {
document.body.addEventListener('scroll', this.onScroll, { passive: true }); document.body.addEventListener('scroll', this.onScroll, { passive: true });
} }
protected elapsed(date: Date): string {
const fmt = 'time.diff-format';
const td = getTimeDiff(date);
const diff = Math.floor(td.diff);
if( diff == 0 ){
return this.$t(fmt, { elapsed: this.$t(td.one) }).toString();
}
if( diff > 1 ){ // plural
return this.$t(fmt, { elapsed: this.$t(td.plural, { n: diff }) }).toString();
}
// singular
return this.$t(fmt, { elapsed: this.$t(td.one, { n: diff }) }).toString();
}
private onScroll(e: Event) { private onScroll(e: Event) {
const target = e.target as HTMLElement; const target = e.target as HTMLElement;
const header = this.$refs.header as HTMLElement; const header = this.$refs.header as HTMLElement;
@ -449,6 +456,8 @@ export default class Timeline extends Vue {
margin-bottom: .4em; margin-bottom: .4em;
user-select: none; user-select: none;
font-size: .7em;
} }
} }
@ -458,6 +467,7 @@ export default class Timeline extends Vue {
width: 50vw; width: 50vw;
font-size: .8em; font-size: .8em;
text-align: justify;
padding: 1em; padding: 1em;
padding-bottom: 2em; padding-bottom: 2em;

View File

@ -12,5 +12,82 @@
"timeline.title": "Timeline of projects featuring", "timeline.title": "Timeline of projects featuring",
"timeline.back": "Change skill", "timeline.back": "Change skill",
"tag.all": "All",
"tag.web": "Web",
"tag.storage": "Storage",
"tag.ui": "UI/UX",
"tag.system": "System",
"tag.mobile": "Mobile",
"tag.network": "Network",
"tag.iot": "IoT",
"tag.organization": "Organization",
"tag.language": "Language",
"tag.human": "Human",
"tag.other": "Other",
"skill.mariadb": "MariaDB",
"skill.postgres": "PostgreSQL",
"skill.mongo": "MongoDB",
"skill.vue": "Vue <i>(.js)</i>",
"skill.angular": "Angular <i>(7+)</i>",
"skill.parcel": "Parcel",
"skill.cordova": "Apache Cordova",
"skill.webpack": "Webpack",
"skill.webgl": "WebGL",
"skill.audioapi": "Audio API",
"skill.websocket": "Websocket",
"skill.docker": "Docker",
"skill.bash": "bash",
"skill.linux": "GNU/Linux",
"skill.systemd": "systemd",
"skill.git": "Git",
"skill.rpm": "RPM packaging",
"skill.raspberry": "Raspberry",
"skill.arduino": "Arduino",
"skill.php": "PHP",
"skill.html": "HTML5",
"skill.css": "CSS3",
"skill.js": "Javascript",
"skill.ajax": "AJAX",
"skill.ts": "Typescript",
"skill.c": "C (lang)",
"skill.cpp": "C++",
"skill.python": "Python",
"skill.go": "Go (lang)",
"skill.qt": "Qt",
"skill.opensource": "Open-source",
"skill.electronics": "Electronics",
"skill.web": "Web",
"skill.rest": "REST",
"skill.crypto": "Security/crypto",
"skill.imageprocessing": "Image processing",
"skill.ai": "Artificial Intelligence",
"skill.deeplearning": "Deep Learning",
"skill.neuralnetwork": "Neural Networks",
"skill.opti": "Program optimization",
"skill.sockets": "Sockets",
"skill.concurrency": "Concurrency",
"skill.uiux": "UI/UX",
"skill.inkscape": "Inkscape",
"skill.rnd": "R&D",
"skill.teamlead": "Team Lead",
"time.diff-format": "{elapsed} ago",
"time.some": "sometime",
"time.second": "{n} second", "time.seconds": "{n} seconds",
"time.minute": "{n} minute", "time.minutes": "{n} minutes",
"time.hour": "{n} hour", "time.hours": "{n} hours",
"time.day": "{n} day", "time.days": "{n} days",
"time.month": "{n} month", "time.months": "{n} months",
"time.year": "{n} year", "time.years": "{n} years",
"project.created": "Created",
"project.sources": "Hosted at",
"project.doc": "Documentation at",
"project.end": "Project stopped in",
"project.still": "Project still active",
"end": "" "end": ""
} }

View File

@ -12,5 +12,44 @@
"timeline.title": "Chronologie des projets avec", "timeline.title": "Chronologie des projets avec",
"timeline.back": "Choisir compétence", "timeline.back": "Choisir compétence",
"tag.all": "Tout",
"tag.web": "Web",
"tag.storage": "Stockage",
"tag.ui": "UI/UX",
"tag.system": "Système",
"tag.mobile": "Mobile",
"tag.network": "Réseau",
"tag.iot": "IoT",
"tag.organization": "Organisation",
"tag.language": "Langage",
"tag.human": "Humain",
"tag.other": "Autre",
"skill.electronics": "Electronique",
"skill.crypto": "Securité/crypto",
"skill.imageprocessing": "Traitement d'image",
"skill.ai": "Intelligence Artificielle",
"skill.neuralnetwork": "Réseaux de neuronnes",
"skill.opti": "Optimization",
"skill.concurrency": "Programmation Concurrente",
"skill.teamlead": "Chef d'équipe",
"time.diff-format": "il y a {elapsed}",
"time.some": "un moment",
"time.second": "{n} seconde", "time.seconds": "{n} secondes",
"time.minute": "{n} minute", "time.minutes": "{n} minutes",
"time.hour": "{n} heure", "time.hours": "{n} heures",
"time.day": "{n} jour", "time.days": "{n} jours",
"time.month": "{n} mois", "time.months": "{n} mois",
"time.year": "{n} an", "time.years": "{n} ans",
"project.created": "Création de",
"project.sources": "Sources:",
"project.doc": "Documentation:",
"project.end": "Projet terminé en",
"project.still": "Projet toujours actif",
"end": "" "end": ""
} }

View File

@ -1,3 +1,4 @@
import { Locales } from '@/locales';
import { tID as s } from './skills'; import { tID as s } from './skills';
export interface Link { export interface Link {
@ -11,7 +12,7 @@ export interface Project {
client: string|null; client: string|null;
started_at: Date; started_at: Date;
stopped_at: Date|null; stopped_at: Date|null;
info: string; info: { [loc in Locales]: string };
source: Link|null; source: Link|null;
doc: Link|null; doc: Link|null;
commits: number; commits: number;
@ -24,7 +25,10 @@ export const Projects: Project[] = [
skills: [s.Angular, s.RnD, s.Concurrency, s.Html, s.Css, s.Inkscape, s.UIUX, s.Ts, s.Js, s.Ajax, s.Cordova, s.Bash, s.Git, s.Rest, s.Rpm, s.Vue, s.Web, s.Docker], skills: [s.Angular, s.RnD, s.Concurrency, s.Html, s.Css, s.Inkscape, s.UIUX, s.Ts, s.Js, s.Ajax, s.Cordova, s.Bash, s.Git, s.Rest, s.Rpm, s.Vue, s.Web, s.Docker],
started_at: new Date(2019, 10, 26), started_at: new Date(2019, 10, 26),
stopped_at: new Date(2021, 4, 11), stopped_at: new Date(2021, 4, 11),
info: 'Prototype for a front-end Angular modular system. I technically and visually designed a kind of app store. Hacked angular to allow injecting custom pages and code on-the-go.', info: {
[Locales.EN]: 'Prototype for a front-end Angular modular system. I technically and visually designed a kind of app store. Hacked angular to allow injecting custom pages and code on-the-go.',
[Locales.FR]: 'Prototype pour rendre un front-end Angular entièrement modulaire. J\'ai du concevoir (techniquement et visuellement) une sorte d\'App store permettant de sélectionner les modules à installer. D\'autre part j\'ai du en quelque sorte hacker angular afin qu\'il permette d\'y injecter des composants (interface) et des services (code) externes en temps réel.',
},
source: null, doc: null, source: null, doc: null,
commits: 0, // ??? commits: 0, // ???
}, },
@ -34,17 +38,23 @@ export const Projects: Project[] = [
skills: [s.Qt, s.RnD, s.Cpp, s.Concurrency, s.Git, s.Css, s.Inkscape, s.UIUX], skills: [s.Qt, s.RnD, s.Cpp, s.Concurrency, s.Git, s.Css, s.Inkscape, s.UIUX],
started_at: new Date(2019, 10, 26), started_at: new Date(2019, 10, 26),
stopped_at: new Date(2021, 4, 11), stopped_at: new Date(2021, 4, 11),
info: 'TODO', info: {
[Locales.EN]: 'TODO',
[Locales.FR]: 'TODO',
},
source: null, doc: null, source: null, doc: null,
commits: 840, commits: 840,
}, },
{ {
name: 'ADSBOnPED', name: 'ADSBOnPED',
client: 'Collins Aerospace', client: 'Collins Aerospace',
skills: [s.Qt, s.RnD, s.Cpp, s.Concurrency, s.Git, s.Css, s.Bash, s.Linux, s.Inkscape, s.UIUX], skills: [s.Qt, s.RnD, s.Cpp, s.Concurrency, s.Git, s.Css, s.Bash, s.Linux, s.Inkscape, s.UIUX, s.TeamLead],
started_at: new Date(2020, 7, 16), started_at: new Date(2020, 7, 16),
stopped_at: null, stopped_at: null,
info: 'TODO', info: {
[Locales.EN]: 'TODO',
[Locales.FR]: 'TODO',
},
source: null, doc: null, source: null, doc: null,
commits: 1897 + 62, commits: 1897 + 62,
}, },
@ -54,7 +64,10 @@ export const Projects: Project[] = [
skills: [s.Go, s.Rest, s.Concurrency, s.Git, s.Bash, s.Linux, s.Docker, s.Crypto, s.Postgres, s.Opti, s.Websocket, s.Inkscape, s.UIUX], skills: [s.Go, s.Rest, s.Concurrency, s.Git, s.Bash, s.Linux, s.Docker, s.Crypto, s.Postgres, s.Opti, s.Websocket, s.Inkscape, s.UIUX],
started_at: new Date(2021, 1, 6), started_at: new Date(2021, 1, 6),
stopped_at: new Date(2022, 11, 1), stopped_at: new Date(2022, 11, 1),
info: 'TODO', info: {
[Locales.EN]: 'TODO',
[Locales.FR]: 'TODO',
},
source: null, doc: null, source: null, doc: null,
commits: 1260 + 90 + 41 + 1 + 12 + 1 + 14, commits: 1260 + 90 + 41 + 1 + 12 + 1 + 14,
}, },
@ -65,7 +78,10 @@ export const Projects: Project[] = [
skills: [s.Go, s.Web, s.Rest, s.OpenSource, s.Git, s.Inkscape], skills: [s.Go, s.Web, s.Rest, s.OpenSource, s.Git, s.Inkscape],
started_at: new Date(2018, 5, 19), started_at: new Date(2018, 5, 19),
stopped_at: null, // still active stopped_at: null, // still active
info: 'Started as a personal go library to ease REST API development. The main goal is to greatly enhance maintainability by providing a single configuration file that describes every endpoint of the API. Everything that can be automated is while staying idiomatic to go. Aicra automates routing, parameter validation and extraction, permission management, response output formatting. I then used it for a professional project in the medical field after corporate evaluation and audit.', info: {
[Locales.EN]: 'Started as a personal go library to ease REST API development. The main goal is to greatly enhance maintainability by providing a single configuration file that describes every endpoint of the API. Everything that can be automated is while staying idiomatic to go. Aicra automates routing, parameter validation and extraction, permission management, response output formatting.<br><br>I then used it for a professional project in the medical field after corporate evaluation and audit. At the end of the project, results in production are promising : development and testing speed and ease, overall performances, configuration readability for other team members provides a real benefit, they can know the whole api at any time.',
[Locales.FR]: 'Démarré en tant que projet personnel afin de simplifier mes développements d\'API REST. L\'objectif principal et d\'améliorer significativement la maintenabilité avec l\'utilisation d\'un fichier de configuration unique qui décrit/définit tous les endpoints de l\'API. Tout ce qui peut être automatisé l\'est tout en restant idiomatique à Go. Aicra automatise le routage, la validation et extraction des paramètres, les classes de permissions, le formattage des réponses, etc.<br><br>J\'ai ensuite pu utiliser cette librairie lors d\'un projet industriel dans le domaine médical après audit et evaluation par l\'entreprise. Après avoir terminé ce projet, les résultats sont plutôt encourageants : rapidité de développement et de test, performances, lisibilité du fichier de configuration pour les autres membres de l\'équipe, (permet de connaître toute l\'API à tout moment du développement) etc.',
},
source: { name: 'github.com/xdrm-io/aicra', link: 'https://github.com/xdrm-io/aicra' }, source: { name: 'github.com/xdrm-io/aicra', link: 'https://github.com/xdrm-io/aicra' },
doc: { name: 'pkg.go.dev/github.com/xdrm-io/aicra', link: 'https://pkg.go.dev/github.com/xdrm-io/aicra' }, doc: { name: 'pkg.go.dev/github.com/xdrm-io/aicra', link: 'https://pkg.go.dev/github.com/xdrm-io/aicra' },
commits: 535, commits: 535,

View File

@ -44,13 +44,96 @@ export enum tID {
UIUX, UIUX,
Inkscape, Inkscape,
RnD, RnD,
TeamLead,
}
export enum tTag {
All,
Web,
Storage,
UI,
System,
Mobile,
Network,
IoT,
Organization,
Language,
Human,
Other
}
export function tagLabel(t: tTag): string {
switch(t){
case tTag.All: return 'tag.all';
case tTag.Web: return 'tag.web';
case tTag.Storage: return 'tag.storage';
case tTag.UI: return 'tag.ui';
case tTag.System: return 'tag.system';
case tTag.Mobile: return 'tag.mobile';
case tTag.Network: return 'tag.network';
case tTag.IoT: return 'tag.iot';
case tTag.Organization: return 'tag.organization';
case tTag.Language: return 'tag.language';
case tTag.Human: return 'tag.human';
case tTag.Other: return 'tag.other';
}
}
export function skillLabel(s: tID): string {
switch(s){
case tID.MariaDB: return 'skill.mariadb';
case tID.Postgres: return 'skill.postgres';
case tID.Mongo: return 'skill.mongo';
case tID.Vue: return 'skill.vue';
case tID.Angular: return 'skill.angular';
case tID.Parcel: return 'skill.parcel';
case tID.Cordova: return 'skill.cordova';
case tID.Webpack: return 'skill.webpack';
case tID.WebGL: return 'skill.webgl';
case tID.AudioAPI: return 'skill.audioapi';
case tID.Websocket: return 'skill.websocket';
case tID.Docker: return 'skill.docker';
case tID.Bash: return 'skill.bash';
case tID.Linux: return 'skill.linux';
case tID.Systemd: return 'skill.systemd';
case tID.Git: return 'skill.git';
case tID.Rpm: return 'skill.rpm';
case tID.RaspBerry: return 'skill.raspberry';
case tID.Arduino: return 'skill.arduino';
case tID.Php: return 'skill.php';
case tID.Html: return 'skill.html';
case tID.Css: return 'skill.css';
case tID.Js: return 'skill.js';
case tID.Ajax: return 'skill.ajax';
case tID.Ts: return 'skill.ts';
case tID.C: return 'skill.c';
case tID.Cpp: return 'skill.cpp';
case tID.Python: return 'skill.python';
case tID.Go: return 'skill.go';
case tID.Qt: return 'skill.qt';
case tID.OpenSource: return 'skill.opensource';
case tID.Electronics: return 'skill.electronics';
case tID.Web: return 'skill.web';
case tID.Rest: return 'skill.rest';
case tID.Crypto: return 'skill.crypto';
case tID.ImageProcessing: return 'skill.imageprocessing';
case tID.AI: return 'skill.ai';
case tID.DeepLearning: return 'skill.deeplearning';
case tID.NeuralNetwork: return 'skill.neuralnetwork';
case tID.Opti: return 'skill.opti';
case tID.Sockets: return 'skill.sockets';
case tID.Concurrency: return 'skill.concurrency';
case tID.UIUX: return 'skill.uiux';
case tID.Inkscape: return 'skill.inkscape';
case tID.RnD: return 'skill.rnd';
case tID.TeamLead: return 'skill.teamlead';
}
} }
export interface tSkill { export interface tSkill {
icon: string|null; icon: string|null;
name: string;
link: string; link: string;
tags: string[]; tags: tTag[];
info: string; info: string;
} }
@ -58,325 +141,286 @@ export type tSkills = { [id in tID]: tSkill };
export const Skills: tSkills = { export const Skills: tSkills = {
[tID.MariaDB]: { [tID.MariaDB]: {
name: 'MariaDB',
link: 'https://mariadb.org', link: 'https://mariadb.org',
icon: 'skills/mariadb.svg', icon: 'skills/mariadb.svg',
tags: ['web', 'storage'], tags: [tTag.Web, tTag.Storage],
info: 'I started using mysql then MariaDB as my first introduction to SQL, mostly when I started learning web with PHP. I now prefer using postgreSQL instead as it tends to be more robust and performant overall.', info: 'I started using mysql then MariaDB as my first introduction to SQL, mostly when I started learning web with PHP. I now prefer using postgreSQL instead as it tends to be more robust and performant overall.',
}, },
[tID.Postgres]: { [tID.Postgres]: {
name: 'PostgreSQL',
link: 'https://postgresql.org', link: 'https://postgresql.org',
icon: 'skills/postgres.svg', icon: 'skills/postgres.svg',
tags: ['web', 'storage'], tags: [tTag.Web, tTag.Storage],
info: 'My main choice of dbms when using sql orfor relational databases. Had some experience with it mainly with go services with docker.', info: 'My main choice of dbms when using sql orfor relational databases. Had some experience with it mainly with go services with docker.',
}, },
[tID.Mongo]: { [tID.Mongo]: {
name: 'MongoDB',
link: 'https://mongodb.com', link: 'https://mongodb.com',
icon: 'skills/mongo.svg', icon: 'skills/mongo.svg',
tags: ['web', 'storage'], tags: [tTag.Web, tTag.Storage],
info: 'I learned it during my Master\'s degree. I used advanced Mongo with schema validation and complex filter requests. I find this technology really interesting over SQL, but I find classical relational databases are easier to comprehend and I am more used to it.', info: 'I learned it during my Master\'s degree. I used advanced Mongo with schema validation and complex filter requests. I find this technology really interesting over SQL, but I find classical relational databases are easier to comprehend and I am more used to it.',
}, },
[tID.Vue]: { [tID.Vue]: {
name: 'Vue <i>(.js)</i>',
link: 'https://vuejs.org', link: 'https://vuejs.org',
icon: 'skills/vue.svg', icon: 'skills/vue.svg',
tags: ['web', 'UI'], tags: [tTag.Web, tTag.UI],
info: 'I started learning Vue (.js) back in 2016, and never stopped practicing since then for personal and professional projects. I view it as a better alternative than angular which provides you with a strict framework that can lack flexibility among teams and projects.<br><br>Vue makes it your responsability to properly structure your project which I like to take care of myself, as it tends to provide a better workflow adjusted for every project.<br><br>It is my top choice when considering a web framework for rendering pages.', info: 'I started learning Vue (.js) back in 2016, and never stopped practicing since then for personal and professional projects. I view it as a better alternative than angular which provides you with a strict framework that can lack flexibility among teams and projects.<br><br>Vue makes it your responsability to properly structure your project which I like to take care of myself, as it tends to provide a better workflow adjusted for every project.<br><br>It is my top choice when considering a web framework for rendering pages.',
}, },
[tID.Angular]: { [tID.Angular]: {
name: 'Angular <i>(7+)</i>',
link: 'https://angular.io', link: 'https://angular.io',
icon: 'skills/angular.svg', icon: 'skills/angular.svg',
tags: ['web', 'UI'], tags: [tTag.Web, tTag.UI],
info: 'I used it only once to break it apart in a R&D project. I had to "hack" it in order to inject services and components on-the-fly.<br><br>You had a kind of App store where you could install modules. The Angular-powered website would inject new navigation menus, pages and services according to the modules you had installed.<br><br>I do not like Angular, as I think Vue.js does a better job achieving the same goal with a cleaner API, and does not force you to embrace the Angular/Google way of coding and organizing things.', info: 'I used it only once to break it apart in a R&D project. I had to "hack" it in order to inject services and components on-the-fly.<br><br>You had a kind of App store where you could install modules. The Angular-powered website would inject new navigation menus, pages and services according to the modules you had installed.<br><br>I do not like Angular, as I think Vue.js does a better job achieving the same goal with a cleaner API, and does not force you to embrace the Angular/Google way of coding and organizing things.',
}, },
[tID.Parcel]: { [tID.Parcel]: {
name: 'Parcel',
link: 'https://parceljs.org/', link: 'https://parceljs.org/',
icon: 'skills/parcel.svg', icon: 'skills/parcel.svg',
tags: ['web'], tags: [tTag.Web],
info: 'I used it often back in my Master\'s Degree period along with PHP backends. It allows to get away from webpack which I find overly complicated and a major point of failure for most frontends.<br><br>I haven\'t used it in a while but would highly consider it as it has no real prerequisite.', info: 'I used it often back in my Master\'s Degree period along with PHP backends. It allows to get away from webpack which I find overly complicated and a major point of failure for most frontends.<br><br>I haven\'t used it in a while but would highly consider it as it has no real prerequisite.',
}, },
[tID.Cordova]: { [tID.Cordova]: {
name: 'Apache Cordova',
link: 'https://cordova.apache.org/', link: 'https://cordova.apache.org/',
icon: 'skills/cordova.svg', icon: 'skills/cordova.svg',
tags: ['system', 'web', 'mobile'], tags: [tTag.System, tTag.Web, tTag.Mobile],
info: 'I used it often to transform single-page applications into android, iOS or desktop apps at low cost. I haven\'t needed this kind of software for a while, it might now be favorable to use Capacitor or other "alternatives".', info: 'I used it often to transform single-page applications into android, iOS or desktop apps at low cost. I haven\'t needed this kind of software for a while, it might now be favorable to use Capacitor or other "alternatives".',
}, },
[tID.Webpack]: { [tID.Webpack]: {
name: 'Webpack',
link: 'https://webpack.js.org/', link: 'https://webpack.js.org/',
icon: 'skills/webpack.svg', icon: 'skills/webpack.svg',
tags: ['web'], tags: [tTag.Web],
info: '... I used it a lot because it is often required. But I hate that it is so complex that most users use it without understanding what is really does. I avoid it whenever possible, the issue can be transposed to node_modules and the whole node ecosystem.', info: '... I used it a lot because it is often required. But I hate that it is so complex that most users use it without understanding what is really does. I avoid it whenever possible, the issue can be transposed to node_modules and the whole node ecosystem.',
}, },
[tID.WebGL]: { [tID.WebGL]: {
name: 'WebGL',
link: 'https://www.khronos.org/webgl/', link: 'https://www.khronos.org/webgl/',
icon: null, icon: null,
tags: ['web'], tags: [tTag.Web],
info: 'I used it during my graduation years, the potential is great but I need to find a time to explore what\'s new.', info: 'I used it during my graduation years, the potential is great but I need to find a time to explore what\'s new.',
}, },
[tID.AudioAPI]: { [tID.AudioAPI]: {
name: 'Audio API',
link: 'https://webaudio.github.io/web-audio-api/', link: 'https://webaudio.github.io/web-audio-api/',
icon: null, icon: null,
tags: ['web'], tags: [tTag.Web],
info: 'I used it mainly to build a discord clone (audio and video full-duplex streaming) as a school project. I also tried the Fourier transform to build nice graphics (c.f. Soundcloud) but have not succeeded at the time.', info: 'I used it mainly to build a discord clone (audio and video full-duplex streaming) as a school project. I also tried the Fourier transform to build nice graphics (c.f. Soundcloud) but have not succeeded at the time.',
}, },
[tID.Websocket]: { [tID.Websocket]: {
name: 'Websocket',
link: 'https://tools.ietf.org/html/rfc6455', link: 'https://tools.ietf.org/html/rfc6455',
icon: null, icon: null,
tags: ['web', 'networking', 'IoT'], tags: [tTag.Web, tTag.Network, tTag.IoT],
info: 'I use them whenever possible to avoid the classical expensive polling.<br><br>I also created my own websocket client & server implementation in Go following nothing but the RFC for learning purposes.<br><br>I\'ve used, designed and implemented websocket communications among personal and professional projects.', info: 'I use them whenever possible to avoid the classical expensive polling.<br><br>I also created my own websocket client & server implementation in Go following nothing but the RFC for learning purposes.<br><br>I\'ve used, designed and implemented websocket communications among personal and professional projects.',
}, },
[tID.Docker]: { [tID.Docker]: {
name: 'Docker',
link: 'https://docker.com', link: 'https://docker.com',
icon: 'skills/docker.svg', icon: 'skills/docker.svg',
tags: ['web', 'system'], tags: [tTag.Web, tTag.System],
info: 'I am using it for a while now. Most of my go projects use it as it costs no memory for your executable (multi-stage build from scratch) and allows for isolation and a better control over the running environment. I am learning docker a bit more every time I use it. It is often coupled with docker-compose in my projects.', info: 'I am using it for a while now. Most of my go projects use it as it costs no memory for your executable (multi-stage build from scratch) and allows for isolation and a better control over the running environment. I am learning docker a bit more every time I use it. It is often coupled with docker-compose in my projects.',
}, },
[tID.Bash]: { [tID.Bash]: {
name: 'bash',
link: 'https://www.gnu.org/software/bash/', link: 'https://www.gnu.org/software/bash/',
icon: null, icon: null,
tags: ['system'], tags: [tTag.System],
info: 'Felt in love with GNU/linux and its ecosystem a while back (was 14yo back then) and I\'ve never stopped. I\'m often the linux/bash guy of the team.<br><br>I use it extensively to automate anything a human can do as it avoids a lot of mistakes in most workflows.', info: 'Felt in love with GNU/linux and its ecosystem a while back (was 14yo back then) and I\'ve never stopped. I\'m often the linux/bash guy of the team.<br><br>I use it extensively to automate anything a human can do as it avoids a lot of mistakes in most workflows.',
}, },
[tID.Linux]: { [tID.Linux]: {
name: 'GNU/Linux',
link: 'https://www.linux.org', link: 'https://www.linux.org',
icon: 'skills/linux.svg', icon: 'skills/linux.svg',
tags: ['system'], tags: [tTag.System],
info: 'Felt in love with GNU/linux and its ecosystem a while back (was 14yo back then) and I\'ve never stopped. <br><br>Linux has been my main OS choice since then. I stepped through Ubuntu, Debian, Manjaro, Elementary, Tails (live), and I am now on Solus for a few years.', info: 'Felt in love with GNU/linux and its ecosystem a while back (was 14yo back then) and I\'ve never stopped. <br><br>Linux has been my main OS choice since then. I stepped through Ubuntu, Debian, Manjaro, Elementary, Tails (live), and I am now on Solus for a few years.',
}, },
[tID.Systemd]: { [tID.Systemd]: {
name: 'systemd',
link: 'https://freedesktop.org/wiki/Software/systemd/', link: 'https://freedesktop.org/wiki/Software/systemd/',
icon: null, icon: null,
tags: ['system'], tags: [tTag.System],
info: '', info: '',
}, },
[tID.Git]: { [tID.Git]: {
name: 'Git',
link: 'https://git-scm.com/', link: 'https://git-scm.com/',
icon: 'skills/git.svg', icon: 'skills/git.svg',
tags: ['system', 'organization'], tags: [tTag.System, tTag.Organization],
info: '', info: '',
}, },
[tID.Rpm]: { [tID.Rpm]: {
name: 'RPM packaging',
link: 'https://rpm.org/', link: 'https://rpm.org/',
icon: null, icon: null,
tags: ['system'], tags: [tTag.System],
info: '', info: '',
}, },
[tID.RaspBerry]: { [tID.RaspBerry]: {
name: 'Raspberry',
link: 'https://raspberrypi.org', link: 'https://raspberrypi.org',
icon: 'skills/raspberry.svg', icon: 'skills/raspberry.svg',
tags: ['system', 'IoT'], tags: [tTag.System, tTag.IoT],
info: '', info: '',
}, },
[tID.Arduino]: { [tID.Arduino]: {
name: 'Arduino',
link: 'https://arduino.cc', link: 'https://arduino.cc',
icon: 'skills/arduino.svg', icon: 'skills/arduino.svg',
tags: ['system', 'IoT'], tags: [tTag.System, tTag.IoT],
info: '', info: '',
}, },
[tID.Php]: { [tID.Php]: {
name: 'PHP',
link: 'https://www.php.net', link: 'https://www.php.net',
icon: 'skills/php.svg', icon: 'skills/php.svg',
tags: ['language', 'web', 'IoT'], tags: [tTag.Language, tTag.Web, tTag.IoT],
info: '', info: '',
}, },
[tID.Html]: { [tID.Html]: {
name: 'HTML5',
link: 'https://www.w3.org/standards/webdesign/htmlcss', link: 'https://www.w3.org/standards/webdesign/htmlcss',
icon: 'skills/html.svg', icon: 'skills/html.svg',
tags: ['language', 'web', 'UI'], tags: [tTag.Language, tTag.Web, tTag.UI],
info: '', info: '',
}, },
[tID.Css]: { [tID.Css]: {
name: 'CSS3',
link: 'https://www.w3.org/standards/webdesign/htmlcss', link: 'https://www.w3.org/standards/webdesign/htmlcss',
icon: 'skills/css.svg', icon: 'skills/css.svg',
tags: ['language', 'web', 'UI'], tags: [tTag.Language, tTag.Web, tTag.UI],
info: '', info: '',
}, },
[tID.Js]: { [tID.Js]: {
name: 'Javascript',
link: 'http://www.ecma-international.org/publications-and-standards/standards/ecma-262/', link: 'http://www.ecma-international.org/publications-and-standards/standards/ecma-262/',
icon: 'skills/js.svg', icon: 'skills/js.svg',
tags: ['language', 'web', 'UI'], tags: [tTag.Language, tTag.Web, tTag.UI],
info: '', info: '',
}, },
[tID.Ajax]: { [tID.Ajax]: {
name: 'AJAX',
link: 'https://www.w3schools.com/xml/ajax_intro.asp', link: 'https://www.w3schools.com/xml/ajax_intro.asp',
icon: null, icon: null,
tags: ['web', 'networking'], tags: [tTag.Web, tTag.Network],
info: '', info: '',
}, },
[tID.Ts]: { [tID.Ts]: {
name: 'Typescript',
link: 'https://www.typescript.org/', link: 'https://www.typescript.org/',
icon: 'skills/ts.svg', icon: 'skills/ts.svg',
tags: ['language', 'web', 'UI'], tags: [tTag.Language, tTag.Web, tTag.UI],
info: '', info: '',
}, },
[tID.C]: { [tID.C]: {
name: 'C (lang)',
link: 'https://www.open-std.org/jtc1/sc22/wg14/', link: 'https://www.open-std.org/jtc1/sc22/wg14/',
icon: 'skills/c.svg', icon: 'skills/c.svg',
tags: ['language', 'system'], tags: [tTag.Language, tTag.System],
info: '', info: '',
}, },
[tID.Cpp]: { [tID.Cpp]: {
name: 'C++',
link: 'https://isocpp.org/', link: 'https://isocpp.org/',
icon: 'skills/cpp.svg', icon: 'skills/cpp.svg',
tags: ['language', 'system'], tags: [tTag.Language, tTag.System],
info: '', info: '',
}, },
[tID.Python]: { [tID.Python]: {
name: 'Python',
link: 'https://python.org/', link: 'https://python.org/',
icon: 'skills/python.svg', icon: 'skills/python.svg',
tags: ['language', 'system'], tags: [tTag.Language, tTag.System],
info: '', info: '',
}, },
[tID.Go]: { [tID.Go]: {
name: 'Go (lang)',
link: 'https://go.dev', link: 'https://go.dev',
icon: 'skills/go.svg', icon: 'skills/go.svg',
tags: ['language', 'system', 'IoT', 'networking'], tags: [tTag.Language, tTag.System, tTag.IoT, tTag.Network],
info: '', info: '',
}, },
[tID.Qt]: { [tID.Qt]: {
name: 'Qt',
link: 'https://qt.io', link: 'https://qt.io',
icon: 'skills/qt.svg', icon: 'skills/qt.svg',
tags: ['language', 'system', 'IoT', 'networking'], tags: [tTag.Language, tTag.System, tTag.IoT, tTag.Network],
info: '', info: '',
}, },
[tID.OpenSource]: { [tID.OpenSource]: {
name: 'Open-source',
link: 'https://opensource.org/', link: 'https://opensource.org/',
icon: null, icon: null,
tags: ['human'], tags: [tTag.Human],
info: '', info: '',
}, },
[tID.Electronics]: { [tID.Electronics]: {
name: 'Electronics',
link: 'https://en.wikipedia.org/wiki/Electronics', link: 'https://en.wikipedia.org/wiki/Electronics',
icon: 'skills/electronics.svg', icon: 'skills/electronics.svg',
tags: ['other', 'IoT'], tags: [tTag.Other, tTag.IoT],
info: '', info: '',
}, },
[tID.Web]: { [tID.Web]: {
name: 'Web',
link: 'https://en.wikipedia.org/wiki/World_Wide_Web', link: 'https://en.wikipedia.org/wiki/World_Wide_Web',
icon: null, icon: null,
tags: ['web'], tags: [tTag.Web],
info: '', info: '',
}, },
[tID.Rest]: { [tID.Rest]: {
name: 'REST',
link: 'https://en.wikipedia.org/wiki/Representational_state_transfer', link: 'https://en.wikipedia.org/wiki/Representational_state_transfer',
icon: null, icon: null,
tags: ['web', 'networking'], tags: [tTag.Web, tTag.Network],
info: '', info: '',
}, },
[tID.Crypto]: { [tID.Crypto]: {
name: 'Security/crypto',
link: 'https://en.wikipedia.org/wiki/Cryptography', link: 'https://en.wikipedia.org/wiki/Cryptography',
icon: 'skills/security.svg', icon: 'skills/security.svg',
tags: ['system', 'networking'], tags: [tTag.System, tTag.Network],
info: '', info: '',
}, },
[tID.ImageProcessing]: { [tID.ImageProcessing]: {
name: 'Image processing',
link: 'https://en.wikipedia.org/wiki/Digital_image_processing', link: 'https://en.wikipedia.org/wiki/Digital_image_processing',
icon: 'skills/image-processing.svg', icon: 'skills/image-processing.svg',
tags: ['system'], tags: [tTag.System],
info: '', info: '',
}, },
[tID.AI]: { [tID.AI]: {
name: 'Artificial Intelligence',
link: 'https://en.wikipedia.org/wiki/Artificial_intelligence', link: 'https://en.wikipedia.org/wiki/Artificial_intelligence',
icon: null, icon: null,
tags: ['other'], tags: [tTag.Other],
info: '', info: '',
}, },
[tID.DeepLearning]: { [tID.DeepLearning]: {
name: 'Deep Learning',
link: 'https://en.wikipedia.org/wiki/Deep_learning', link: 'https://en.wikipedia.org/wiki/Deep_learning',
icon: null, icon: null,
tags: ['other'], tags: [tTag.Other],
info: '', info: '',
}, },
[tID.NeuralNetwork]: { [tID.NeuralNetwork]: {
name: 'Neural Networks',
link: 'https://en.wikipedia.org/wiki/Artificial_neural_network', link: 'https://en.wikipedia.org/wiki/Artificial_neural_network',
icon: null, icon: null,
tags: ['other'], tags: [tTag.Other],
info: '', info: '',
}, },
[tID.Opti]: { [tID.Opti]: {
name: 'Program optimization',
link: 'https://en.wikipedia.org/wiki/Program_optimization', link: 'https://en.wikipedia.org/wiki/Program_optimization',
icon: 'skills/opti.svg', icon: 'skills/opti.svg',
tags: ['system', 'networking'], tags: [tTag.System, tTag.Network],
info: '', info: '',
}, },
[tID.Sockets]: { [tID.Sockets]: {
name: 'Sockets',
link: 'https://en.wikipedia.org/wiki/Computer_network_programming', link: 'https://en.wikipedia.org/wiki/Computer_network_programming',
icon: null, icon: null,
tags: ['system', 'networking', 'IoT', 'web'], tags: [tTag.System, tTag.Network, tTag.IoT, tTag.Web],
info: '', info: '',
}, },
[tID.Concurrency]: { [tID.Concurrency]: {
name: 'Concurrency',
link: 'https://en.wikipedia.org/wiki/Concurrent_computing', link: 'https://en.wikipedia.org/wiki/Concurrent_computing',
icon: null, icon: null,
tags: ['system', 'networking'], tags: [tTag.System, tTag.Network],
info: '', info: '',
}, },
[tID.UIUX]: { [tID.UIUX]: {
name: 'UI/UX',
link: 'https://en.wikipedia.org/wiki/UX', link: 'https://en.wikipedia.org/wiki/UX',
icon: null, icon: null,
tags: ['system', 'web', 'IoT'], tags: [tTag.System, tTag.Web, tTag.IoT],
info: '', info: '',
}, },
[tID.Inkscape]: { [tID.Inkscape]: {
name: 'Inkscape',
link: 'https://inkscape.org/', link: 'https://inkscape.org/',
icon: 'skills/inkscape.svg', icon: 'skills/inkscape.svg',
tags: ['UI', 'web', 'organization'], tags: [tTag.UI, tTag.Web, tTag.Organization],
info: '', info: '',
}, },
[tID.RnD]: { [tID.RnD]: {
name: 'R&D',
link: 'https://en.wikipedia.org/wiki/R&D', link: 'https://en.wikipedia.org/wiki/R&D',
icon: null, icon: null,
tags: ['organization'], tags: [tTag.Organization, tTag.Other],
info: '',
},
[tID.TeamLead]: {
link: 'https://en.wikipedia.org/wiki/Team_leader',
icon: null,
tags: [tTag.Organization, tTag.Human,],
info: '', info: '',
}, },
}; };

View File

@ -1,7 +1,7 @@
import { tID, Skills, tSkill } from '@/model/skills'; import { tID, Skills, tSkill, tTag } from '@/model/skills';
let availCache: tID[]|null = null; let availCache: tID[]|null = null;
let tagsCache: string[]|null = null; let tagsCache: tTag[]|null = null;
// returns available skill ids. // returns available skill ids.
export function available(): tID[] { export function available(): tID[] {
@ -22,7 +22,7 @@ export function available(): tID[] {
// returns the list of ids filtered by a tag. Skills NOT featuring the provided // returns the list of ids filtered by a tag. Skills NOT featuring the provided
// tag are filtered out of the list. // tag are filtered out of the list.
export function filtered(tag: string): tID[] { export function filtered(tag: tTag): tID[] {
if ( availCache == null ) { if ( availCache == null ) {
available(); available();
} }
@ -42,7 +42,7 @@ export function filtered(tag: string): tID[] {
} }
// returns available tags used among skills // returns available tags used among skills
export function tags(): string[] { export function tags(): tTag[] {
if ( tagsCache != null ) { if ( tagsCache != null ) {
return tagsCache; return tagsCache;
} }