feat: SEO, accessibility
This commit is contained in:
parent
e1aa5b948a
commit
71ff315897
|
@ -9,10 +9,12 @@
|
||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link rel="preload" href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro&display=swap" as="style">
|
<link rel="preload" href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro|Fira%20Code&display=swap" as="style">
|
||||||
<link rel="stylesheet"href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro&display=swap" media="all">
|
<link rel="stylesheet"href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro|Fira%20Code&display=swap" media="all">
|
||||||
|
|
||||||
<title>xdrm()</title>
|
<title>xdrm()</title>
|
||||||
|
<meta name="description" content="Portfolio d'Adrien Marquès, développeur freelance spécialisé en Go et IoT">
|
||||||
|
<meta name="keywords" content="développeur freelance, Go, IoT, web development">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|
|
@ -15,6 +15,10 @@ html, body{
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
11
src/App.vue
11
src/App.vue
|
@ -14,7 +14,6 @@ import Home from './components/Home.vue';
|
||||||
import Timeline from './components/Timeline.vue';
|
import Timeline from './components/Timeline.vue';
|
||||||
import SkillPicker from './components/SkillPicker.vue';
|
import SkillPicker from './components/SkillPicker.vue';
|
||||||
import Footer from './components/Footer.vue';
|
import Footer from './components/Footer.vue';
|
||||||
import { Locales } from './locales';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -26,8 +25,6 @@ import { Locales } from './locales';
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class App extends Vue {
|
export default class App extends Vue {
|
||||||
private selected: tID|null = null;
|
|
||||||
|
|
||||||
// skill picker selection -> filters the timeline
|
// 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;
|
||||||
|
@ -69,7 +66,7 @@ export default class App extends Vue {
|
||||||
|
|
||||||
|
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-family: 'Source Sans Pro';
|
font-family: 'Source Sans Pro', sans-serif;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -86,7 +83,7 @@ export default class App extends Vue {
|
||||||
|
|
||||||
transition: color .2s ease-in-out;
|
transition: color .2s ease-in-out;
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -105,8 +102,8 @@ export default class App extends Vue {
|
||||||
&:hover{
|
&:hover{
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
width: 90%;
|
width: 104%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div id='footer'>
|
<footer id='footer'>
|
||||||
|
<div class='wave' aria-hidden="true"></div>
|
||||||
|
<div class='wave w2' aria-hidden="true"></div>
|
||||||
|
|
||||||
<div class='wave'></div>
|
<div class="footer-content">
|
||||||
<div class='wave w2'></div>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<div class='copyright'>
|
<div class='copyright'>
|
||||||
2022 © xdrm-brackets
|
<p>© {{ currentYear }} xdrm-brackets</p>
|
||||||
<span>Adrien Marquès</span>
|
<p>Adrien Marquès</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img class='logo' src='../assets/home/logo.svg'/>
|
<img class='logo' src='../assets/home/logo.svg' alt='Logo Adrien Marquès' width="64" height="64"/>
|
||||||
|
|
||||||
<div class='contact'>
|
<address class='contact'>
|
||||||
<span>xdrm.io</span>
|
<p>xdrm.io</p>
|
||||||
<span>(+33) 06 69 05 19 10</span>
|
<p><a href="tel:+33669051910">(+33) 06 69 05 19 10</a></p>
|
||||||
<span>xdrm.dev@gmail.com</span>
|
<p><a href="mailto:xdrm.dev@gmail.com">xdrm.dev@gmail.com</a></p>
|
||||||
<span>Montauban, 82000</span>
|
<p>Montauban, 82000</p>
|
||||||
|
</address>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -30,7 +28,9 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||||
components: {},
|
components: {},
|
||||||
})
|
})
|
||||||
export default class Footer extends Vue {
|
export default class Footer extends Vue {
|
||||||
|
get currentYear() {
|
||||||
|
return new Date().getFullYear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -48,26 +48,45 @@ export default class Footer extends Vue {
|
||||||
background: lighten(#202228, 15%);
|
background: lighten(#202228, 15%);
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover, &:focus {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: $wave-height;
|
margin-top: $wave-height;
|
||||||
min-height: 20vh;
|
min-height: 20vh;
|
||||||
|
|
||||||
color: #bcc6ce;
|
color: #bcc6ce;
|
||||||
|
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
font-family: 'Fira Code';
|
font-family: 'Fira Code';
|
||||||
|
}
|
||||||
|
|
||||||
.copyright, .contact {
|
.copyright, .contact {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
span {
|
p {
|
||||||
display: block;
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover, &:focus {
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +98,6 @@ export default class Footer extends Vue {
|
||||||
width: $logo-size;
|
width: $logo-size;
|
||||||
height: $logo-size;
|
height: $logo-size;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes wave-x {
|
@keyframes wave-x {
|
||||||
from{ background-position-x: 1px; }
|
from{ background-position-x: 1px; }
|
||||||
|
@ -109,5 +127,4 @@ export default class Footer extends Vue {
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,36 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<div id='home'>
|
<main id='home'>
|
||||||
|
<LangPicker/>
|
||||||
|
|
||||||
|
<img class='logo' src='../assets/home/logo.svg' alt="Logo Adrien Marquès" width="128" height="128"/>
|
||||||
|
|
||||||
<LangPicker />
|
<header class='name'>
|
||||||
|
|
||||||
<img class='logo' src='../assets/home/logo.svg'/>
|
|
||||||
|
|
||||||
<section class='name'>
|
|
||||||
<h1>Adrien<br>Marquès</h1>
|
<h1>Adrien<br>Marquès</h1>
|
||||||
<br>
|
<p class="job-title">{{ $t('home.title') }}</p>
|
||||||
<br>
|
</header>
|
||||||
<h2>{{ $t('home.title') }}</h2>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<div class='separator'></div>
|
<div class='separator' aria-hidden="true"></div>
|
||||||
|
|
||||||
<section class='readme' ref='test'>
|
<section class='readme' ref='test'>
|
||||||
<div class='header'>README.md</div>
|
<h2 class='header'>README.md</h2>
|
||||||
|
<div class="readme-content">
|
||||||
<p ref='text1'>{{ $t('home.line1') }}</p>
|
<p ref='text1'>{{ $t('home.line1') }}</p>
|
||||||
<p ref='text2'>{{ $t('home.line2-1') }} <u>{{ $t('home.line2-2') }}</u> {{$t('home.line2-3') }}</p>
|
<p ref='text2'>{{ $t('home.line2-1') }} <span class="highlight">{{ $t('home.line2-2') }}</span> {{$t('home.line2-3') }}</p>
|
||||||
<p ref='text3'>{{ $t('home.line3') }}</p>
|
<p ref='text3'>{{ $t('home.line3') }}</p>
|
||||||
<p ref='text4'>{{ $t('home.line4') }}</p>
|
<p ref='text4'>{{ $t('home.line4') }}</p>
|
||||||
<p ref='text5'>{{ $t('home.line5-1') }} <u>Go</u> {{ $t('home.line5-2') }} <u>IoT</u> {{ $t('home.line5-3') }}</p>
|
<p ref='text5'>{{ $t('home.line5-1') }} <span class="highlight">Go</span> {{ $t('home.line5-2') }} <span class="highlight">IoT</span> {{ $t('home.line5-3') }}</p>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class='scroll-arrow' @click='scrollNext()'>
|
<button class='scroll-arrow' @click='scrollNext()' aria-label="Défiler vers la section suivante">
|
||||||
<img src='@/assets/scroll_arrow.svg' />
|
<img src='@/assets/scroll_arrow.svg' alt="" aria-hidden="true" width="40" height="40"/>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<div class='wave'></div>
|
<div class='wave' aria-hidden="true"></div>
|
||||||
<div class='wave w2'></div>
|
<div class='wave w2' aria-hidden="true"></div>
|
||||||
</div>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -38,7 +36,6 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||||
import { go } from '@/service/scroller';
|
import { go } from '@/service/scroller';
|
||||||
import { TypeWriter } from '@/service/typewriter';
|
import { TypeWriter } from '@/service/typewriter';
|
||||||
import LangPicker from './LangPicker.vue';
|
import LangPicker from './LangPicker.vue';
|
||||||
LangPicker;
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { LangPicker },
|
components: { LangPicker },
|
||||||
|
@ -120,6 +117,7 @@ export default class Home extends Vue {
|
||||||
$scroll-btn-size: 5rem;
|
$scroll-btn-size: 5rem;
|
||||||
|
|
||||||
$wave-height: 6.3rem;
|
$wave-height: 6.3rem;
|
||||||
|
$primary-color: #6553d0;
|
||||||
|
|
||||||
#home {
|
#home {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
@ -176,7 +174,7 @@ export default class Home extends Vue {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
h1 { font-size: 7em; font-weight: 800; line-height: 1em; }
|
h1 { font-size: 7em; font-weight: 800; line-height: 1em; }
|
||||||
h2 { font-size: 2.5em; font-weight: 400; white-space: nowrap; }
|
p { font-size: 2.5em; font-weight: 400; white-space: nowrap; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.separator {
|
.separator {
|
||||||
|
@ -228,6 +226,12 @@ export default class Home extends Vue {
|
||||||
border-bottom: .15rem solid #323841;
|
border-bottom: .15rem solid #323841;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1em;
|
||||||
|
// ... autres styles existants ...
|
||||||
|
}
|
||||||
|
|
||||||
|
.readme-content {
|
||||||
p {
|
p {
|
||||||
// typewriter animation changes it
|
// typewriter animation changes it
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -241,38 +245,34 @@ export default class Home extends Vue {
|
||||||
margin-left: calc( 1em + 1.2em );
|
margin-left: calc( 1em + 1.2em );
|
||||||
text-indent: -1.2em;
|
text-indent: -1.2em;
|
||||||
|
|
||||||
u {
|
.highlight {
|
||||||
display: inline;
|
display: inline;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 60%;
|
top: 60%;
|
||||||
left: -.2em;
|
left: -.2em;
|
||||||
width: calc( 100% + 2*.2em );
|
width: calc( 100% + 2*.2em );
|
||||||
height: 30%;
|
height: 30%;
|
||||||
|
background: darken($primary-color, 10%);
|
||||||
background: #6553d0;
|
|
||||||
|
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
z-index: 10;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
content: '> ';
|
content: '> ';
|
||||||
|
|
||||||
color: #6553d0;
|
color: $primary-color;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='lang-picker'>
|
<div class='lang-picker' role="region" aria-label="fr-FR: Sélection de la langue, en-US: Language selection">
|
||||||
<div @click='current = locales[0]' :data-active='current == locales[0]'>
|
<button @click='setLanguage(locales[0])' :aria-pressed='current === locales[0]'>
|
||||||
<img src='../assets/lang/en-US.svg'/>
|
<img src='../assets/lang/en-US.svg' alt="English"/>
|
||||||
</div>
|
<span class="visually-hidden">English</span>
|
||||||
<div @click='current = locales[1]' :data-active='current == locales[1]'>
|
</button>
|
||||||
<img src='../assets/lang/fr-FR.svg'/>
|
<button @click='setLanguage(locales[1])' :aria-pressed='current === locales[1]'>
|
||||||
</div>
|
<img src='../assets/lang/fr-FR.svg' alt="Français"/>
|
||||||
|
<span class="visually-hidden">Français</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -20,28 +22,42 @@ export default class LangPicker extends Vue {
|
||||||
get current(): string {
|
get current(): string {
|
||||||
return this.$i18n.locale;
|
return this.$i18n.locale;
|
||||||
}
|
}
|
||||||
set current(l: string) {
|
|
||||||
localStorage.setItem('lang', l);
|
private setLanguage(lang: string) {
|
||||||
this.$i18n.locale = l;
|
if (this.current !== lang) {
|
||||||
|
localStorage.setItem('lang', lang);
|
||||||
|
this.$i18n.locale = lang;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.announceLanguageChange(lang);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private announceLanguageChange(lang: string) {
|
||||||
|
const announcement = document.createElement('div');
|
||||||
|
announcement.setAttribute('aria-live', 'polite');
|
||||||
|
if (lang === Locales.EN) {
|
||||||
|
announcement.textContent = `Language changed to ${lang === Locales.EN ? 'English' : 'French'}`;
|
||||||
|
} else {
|
||||||
|
announcement.textContent = `La langue a été changée en ${lang === Locales.EN ? 'anglais' : 'français'}`;
|
||||||
|
}
|
||||||
|
document.body.appendChild(announcement);
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.removeChild(announcement);
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private mounted() {
|
private mounted() {
|
||||||
const ls = localStorage.getItem('lang') as Locales|null;
|
const ls = localStorage.getItem('lang') as Locales|null;
|
||||||
|
|
||||||
// already selected a language, stay with it
|
if (ls != null && this.locales.indexOf(ls) >= 0) {
|
||||||
if ( ls != null && this.locales.indexOf(ls) >= 0 ) {
|
this.setLanguage(ls);
|
||||||
this.current = ls;
|
} else if (navigator.language.indexOf('fr') > -1) {
|
||||||
return;
|
this.setLanguage(Locales.FR);
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, go with the navigator's default
|
|
||||||
if ( navigator.language.indexOf('fr') > -1 ) {
|
|
||||||
this.current = Locales.FR;
|
|
||||||
} else {
|
} else {
|
||||||
this.current = Locales.EN;
|
this.setLanguage(Locales.EN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -54,13 +70,14 @@ export default class LangPicker extends Vue {
|
||||||
|
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
|
|
||||||
div {
|
button {
|
||||||
flex: 2em;
|
flex: 2em;
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
padding: .25em;
|
padding: .25em;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
|
||||||
transform-style: preserve-3d;
|
transform-style: preserve-3d;
|
||||||
transition: filter .1s ease-in-out;
|
transition: filter .1s ease-in-out;
|
||||||
|
@ -74,6 +91,10 @@ export default class LangPicker extends Vue {
|
||||||
&:not([data-active=true]):hover {
|
&:not([data-active=true]):hover {
|
||||||
filter: grayscale(40%);
|
filter: grayscale(40%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
filter: grayscale(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
@ -81,4 +102,16 @@ export default class LangPicker extends Vue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.visually-hidden {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='level' >
|
<div class='level' :aria-label="$t('skills.level-display', { level: level })">
|
||||||
<div ref='l1' class='l1'/>
|
<div ref='l1' class='l1' :aria-hidden="true"/>
|
||||||
<div ref='l2' class='l2'/>
|
<div ref='l2' class='l2' :aria-hidden="true"/>
|
||||||
<div ref='l3' class='l3'/>
|
<div ref='l3' class='l3' :aria-hidden="true"/>
|
||||||
<div ref='l4' class='l4'/>
|
<div ref='l4' class='l4' :aria-hidden="true"/>
|
||||||
<div ref='l5' class='l5'/>
|
<div ref='l5' class='l5' :aria-hidden="true"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='skill-card' ref='root' :data-active='active ? "1" : "0"' @click='onClick()' :title='name()'>
|
<div
|
||||||
<img class='icon' :src='icon()' />
|
class='skill-card'
|
||||||
|
ref='root'
|
||||||
|
:data-active='active ? "1" : "0"'
|
||||||
|
@click='onClick()'
|
||||||
|
:title='name()'
|
||||||
|
role="button"
|
||||||
|
:aria-pressed='active'
|
||||||
|
:tabindex="0"
|
||||||
|
@keydown.enter='onClick()'
|
||||||
|
@keydown.space='onClick()'
|
||||||
|
>
|
||||||
|
<img class='icon' :src='icon()' :alt="$t('skills.icon-alt', { skill: name() })"/>
|
||||||
<span class='name'>
|
<span class='name'>
|
||||||
<span v-html='name()'></span>
|
<span v-html='name()'></span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,58 +1,56 @@
|
||||||
<template>
|
<template>
|
||||||
<div id='skill-picker'>
|
<section id='skill-picker' aria-labelledby="skill-picker-title">
|
||||||
|
<h2 id="skill-picker-title" class="visually-hidden">{{ $t('skills.title') }}</h2>
|
||||||
|
|
||||||
<div class='wrapper'>
|
<div class='wrapper'>
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
|
<nav class='categories' aria-label="Catégories de compétences">
|
||||||
<section class='categories'>
|
|
||||||
<SkillCard v-for='(t) of tags'
|
<SkillCard v-for='(t) of tags'
|
||||||
:key='t'
|
:key='t'
|
||||||
:active='t == tag'
|
:active='t == tag'
|
||||||
:folder='$t(tagLabel(t))'
|
:folder='$t(tagLabel(t))'
|
||||||
@pick='onTag(t, $event)'/>
|
@pick='onTag(t, $event)'/>
|
||||||
</section>
|
</nav>
|
||||||
|
|
||||||
<section class='skills'>
|
<div class='skills' role="list" aria-label="Liste des compétences">
|
||||||
<SkillCard v-for='(id) of ids'
|
<SkillCard v-for='(id) of ids'
|
||||||
:key='id'
|
:key='id'
|
||||||
v-show='filtered.indexOf(id) >= 0'
|
v-show='filtered.indexOf(id) >= 0'
|
||||||
:id='id'
|
:id='id'
|
||||||
:active='id == sel'
|
:active='id == sel'
|
||||||
@pick='onPick(id, $event)'/>
|
@pick='onPick(id, $event)'
|
||||||
</section>
|
role="listitem"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section class='details' v-if='details != null'>
|
<section class='details' v-if='details != null' aria-live="polite">
|
||||||
<header>
|
<header>
|
||||||
<span class='interest'>{{ $t('skills.interest') }}<LevelDisplay :level='details.interest'/></span>
|
<span class='interest'>{{ $t('skills.interest') }}<LevelDisplay :level='details.interest'/></span>
|
||||||
<img :src='details.icon'/>
|
<img :src='details.icon' :alt="$t('skills.icon-alt', { skill: details.title })"/>
|
||||||
<span class='mastery'>{{ $t('skills.mastery') }}<LevelDisplay :level='details.mastery'/></span>
|
<span class='mastery'>{{ $t('skills.mastery') }}<LevelDisplay :level='details.mastery'/></span>
|
||||||
</header>
|
</header>
|
||||||
<h1 v-html='details.title'></h1>
|
<h3>{{ details.title }}</h3>
|
||||||
<h2>{{ $t('skills.featured-before') }} <b>{{ details.projects.length }}</b> {{ details.projects.length > 1 ? $t('skills.featured-after-n') : $t('skills.featured-after-1') }}</h2>
|
<h3>{{ $t('skills.featured-before') }} <b class="primary-color">{{ details.projects.length }}</b> {{ details.projects.length > 1 ? $t('skills.featured-after-n') : $t('skills.featured-after-1') }}</h3>
|
||||||
<h3>
|
<p class="project-links">
|
||||||
<template v-for='(proj) of details.projects'>
|
<template v-for='(proj, index) of details.projects'>
|
||||||
<a :key='"pick-" + proj.name' :href='"#" + sanitize(proj.name)' @click='$event.preventDefault(); scroll(sanitize(proj.name));'>
|
<a :key='"pick-" + proj.name' :href='"#" + sanitize(proj.name)' @click.prevent='scroll(sanitize(proj.name))'>
|
||||||
{{ proj.name }}
|
{{ proj.name }}
|
||||||
</a>
|
</a><span v-if="index < details.projects.length - 1" :key='"separator-" + index'>, </span>
|
||||||
<span :key='proj.name'>, </span>
|
|
||||||
</template>
|
</template>
|
||||||
</h3>
|
</p>
|
||||||
<p v-html='details.text[$i18n.locale]'></p>
|
<p v-html='details.text[$i18n.locale]'></p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class='guide' v-else>
|
<section class='guide' v-else aria-live="polite">
|
||||||
<p v-html='$t("skills.guide")'></p>
|
<p v-html='$t("skills.guide")'></p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type='button' v-show='this.sel != null' :value="$t('skills.browse')" @click='browse()'/>
|
<button v-if='this.sel != null' @click='browse()'>{{ $t('skills.browse') }}</button>
|
||||||
<input type='button' v-show='this.sel == null' :value="$t('skills.browse-all')" @click='browse()'/>
|
<button v-else @click='browse()'>{{ $t('skills.browse-all') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='spacer'></div>
|
<div class='spacer' aria-hidden="true"></div>
|
||||||
|
</section>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -210,6 +208,8 @@ export default class SkillPicker extends Vue {
|
||||||
$bottom-spacer: 15vh;
|
$bottom-spacer: 15vh;
|
||||||
$bottom-margin: 10vh;
|
$bottom-margin: 10vh;
|
||||||
|
|
||||||
|
$primary-color: #745cfc;
|
||||||
|
|
||||||
#skill-picker {
|
#skill-picker {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -377,9 +377,11 @@ export default class SkillPicker extends Vue {
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
margin-bottom: 4rem;
|
margin-bottom: 4rem;
|
||||||
|
|
||||||
font-size: 1.7em;
|
font-size: 1.5em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
color: #c1c1c1;
|
color: #c1c1c1;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
|
||||||
|
@ -391,6 +393,21 @@ export default class SkillPicker extends Vue {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.project-links {
|
||||||
|
display: inline;
|
||||||
|
font-size: 1.3em;
|
||||||
|
color: #616c7c;
|
||||||
|
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-color {
|
||||||
|
color: $primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -427,7 +444,7 @@ export default class SkillPicker extends Vue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input, button {
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc( 100% - #{$page-margin} );
|
top: calc( 100% - #{$page-margin} );
|
||||||
|
@ -482,4 +499,16 @@ export default class SkillPicker extends Vue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.visually-hidden {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
{
|
|
||||||
"home.title": "FREELANCE DEVELOPER",
|
|
||||||
"home.line1": "Hi, I am another freelance developer !",
|
|
||||||
"home.line2-1": "I've created this website so you can",
|
|
||||||
"home.line2-2": "browse",
|
|
||||||
"home.line2-3": "my skills and projects.",
|
|
||||||
"home.line3": "I started dev back in 2010. I now have worked on more than 50 projects.",
|
|
||||||
"home.line4": "I work hard to provide my clients with maintainable projects so that they can evolve at low cost (economic and ecological).",
|
|
||||||
"home.line5-1": "My top technologies at the moment are",
|
|
||||||
"home.line5-2": "and",
|
|
||||||
"home.line5-3": "(Arduino, Raspberry).",
|
|
||||||
|
|
||||||
"timeline.title": "Timeline of projects featuring",
|
|
||||||
"timeline.title-all": "Timeline of all projects",
|
|
||||||
"timeline.back": "Change skill",
|
|
||||||
|
|
||||||
"skills.featured-before": "Featured in",
|
|
||||||
"skills.featured-after-1": "project",
|
|
||||||
"skills.featured-after-n": "projects",
|
|
||||||
"skills.browse": "Browse projects",
|
|
||||||
"skills.browse-all": "Browse all projects",
|
|
||||||
"skills.guide": "You can select a skill to browse related projects. You can browse all projects by not selecting or deselecting the active skill.",
|
|
||||||
"skills.interest": "interest level",
|
|
||||||
"skills.mastery": "mastery level",
|
|
||||||
|
|
||||||
"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",
|
|
||||||
"skill.needsanalysis": "Needs analysis",
|
|
||||||
"skill.grpc": "gRPC",
|
|
||||||
"skill.microservices": "Micro services",
|
|
||||||
"skill.kubernetes": "Kubernetes",
|
|
||||||
"skill.scrum": "SCRUM",
|
|
||||||
"skill.lora": "LoRa",
|
|
||||||
"skill.architecture": "Architecture",
|
|
||||||
"skill.chirpstack": "ChirpStack",
|
|
||||||
"skill.refactor": "Refactoring",
|
|
||||||
"skill.timescale": "Timescale",
|
|
||||||
"skill.atlassian": "Atlassian",
|
|
||||||
|
|
||||||
"time.dur-format": "took {duration}",
|
|
||||||
"time.cur-format": "since {duration}",
|
|
||||||
"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",
|
|
||||||
"project.username": "Adrien Marquès",
|
|
||||||
|
|
||||||
"end": ""
|
|
||||||
}
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
export default {
|
||||||
|
'home.title': 'FREELANCE DEVELOPER',
|
||||||
|
'home.line1': 'Hi, I am another freelance developer !',
|
||||||
|
'home.line2-1': 'I\'ve created this website so you can',
|
||||||
|
'home.line2-2': 'browse',
|
||||||
|
'home.line2-3': 'my skills and projects.',
|
||||||
|
'home.line3': 'I started dev back in 2010. I now have worked on more than 50 projects.',
|
||||||
|
'home.line4': 'I work hard to provide my clients with maintainable projects so that they can evolve at low cost (economic and ecological).',
|
||||||
|
'home.line5-1': 'My top technologies at the moment are',
|
||||||
|
'home.line5-2': 'and',
|
||||||
|
'home.line5-3': '(Arduino, Raspberry).',
|
||||||
|
|
||||||
|
'timeline.title': 'Timeline of projects featuring',
|
||||||
|
'timeline.title-all': 'Timeline of all projects',
|
||||||
|
'timeline.back': 'Change skill',
|
||||||
|
|
||||||
|
'skills.featured-before': 'Featured in',
|
||||||
|
'skills.featured-after-1': 'project',
|
||||||
|
'skills.featured-after-n': 'projects',
|
||||||
|
'skills.browse': 'Browse projects',
|
||||||
|
'skills.browse-all': 'Browse all projects',
|
||||||
|
'skills.guide': 'You can select a skill to browse related projects. You can browse all projects by not selecting or deselecting the active skill.',
|
||||||
|
'skills.interest': 'interest level',
|
||||||
|
'skills.mastery': 'mastery level',
|
||||||
|
|
||||||
|
'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',
|
||||||
|
'skill.needsanalysis': 'Needs analysis',
|
||||||
|
'skill.grpc': 'gRPC',
|
||||||
|
'skill.microservices': 'Micro services',
|
||||||
|
'skill.kubernetes': 'Kubernetes',
|
||||||
|
'skill.scrum': 'SCRUM',
|
||||||
|
'skill.lora': 'LoRa',
|
||||||
|
'skill.architecture': 'Architecture',
|
||||||
|
'skill.chirpstack': 'ChirpStack',
|
||||||
|
'skill.refactor': 'Refactoring',
|
||||||
|
'skill.timescale': 'Timescale',
|
||||||
|
'skill.atlassian': 'Atlassian',
|
||||||
|
|
||||||
|
'time.dur-format': 'took {duration}',
|
||||||
|
'time.cur-format': 'since {duration}',
|
||||||
|
'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',
|
||||||
|
'project.username': 'Adrien Marquès',
|
||||||
|
|
||||||
|
'end': ''
|
||||||
|
}
|
|
@ -1,118 +0,0 @@
|
||||||
{
|
|
||||||
"home.title": "DÉVELOPPEUR FREELANCE",
|
|
||||||
"home.line1": "Hello, je suis développeur freelance !",
|
|
||||||
"home.line2-1": "J'ai développé ce site afin de vous permettre de",
|
|
||||||
"home.line2-2": "parcourir",
|
|
||||||
"home.line2-3": "mes compétences et projets.",
|
|
||||||
"home.line3": "J'ai démarré le dev en 2010. Aujourd'hui je compte plus de 50 projets à mon actif.",
|
|
||||||
"home.line4": "Je suis très attaché à fournir à mes clients des projets maintenables afin qu'ils puissent évoluer à moindre coût (économique et écologique).",
|
|
||||||
"home.line5-1": "Les technologies qui m'intéressent actuellement sont le",
|
|
||||||
"home.line5-2": "et l'",
|
|
||||||
"home.line5-3": "(Arduino, Raspberry).",
|
|
||||||
|
|
||||||
"timeline.title": "Chronologie des projets avec",
|
|
||||||
"timeline.title-all": "Chronologie de tous les projets",
|
|
||||||
"timeline.back": "Changer de compétence",
|
|
||||||
|
|
||||||
"skills.featured-before": "Apparaît dans",
|
|
||||||
"skills.featured-after-1": "projet",
|
|
||||||
"skills.featured-after-n": "projets",
|
|
||||||
"skills.browse": "Parcourir les projets",
|
|
||||||
"skills.browse-all": "Parcourir tous les projets",
|
|
||||||
"skills.guide": "Vous pouvez sélectionner une compétence afin de parcourir les projets liés. Vous pouvez aussi parcourir tous les projets en ne sélectionnant pas de compétence.",
|
|
||||||
"skills.interest": "intérêt",
|
|
||||||
"skills.mastery": "maîtrise",
|
|
||||||
|
|
||||||
"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.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": "Electronique",
|
|
||||||
"skill.web": "Web",
|
|
||||||
"skill.rest": "REST",
|
|
||||||
"skill.crypto": "Securité/crypto",
|
|
||||||
"skill.imageprocessing": "Traitement d'image",
|
|
||||||
"skill.ai": "Intelligence Artificielle",
|
|
||||||
"skill.deeplearning": "Deep Learning",
|
|
||||||
"skill.neuralnetwork": "Réseaux de neuronnes",
|
|
||||||
"skill.opti": "Optimization",
|
|
||||||
"skill.sockets": "Sockets",
|
|
||||||
"skill.concurrency": "Programmation Concurrente",
|
|
||||||
"skill.uiux": "UI/UX",
|
|
||||||
"skill.inkscape": "Inkscape",
|
|
||||||
"skill.rnd": "R&D",
|
|
||||||
"skill.teamlead": "Chef d'équipe",
|
|
||||||
"skill.needsanalysis": "Analyse besoin client",
|
|
||||||
"skill.grpc": "gRPC",
|
|
||||||
"skill.microservices": "Micro services",
|
|
||||||
"skill.kubernetes": "Kubernetes",
|
|
||||||
"skill.scrum": "SCRUM",
|
|
||||||
"skill.lora": "LoRa",
|
|
||||||
"skill.architecture": "Architecture",
|
|
||||||
"skill.chirpstack": "ChirpStack",
|
|
||||||
"skill.refactor": "Refactor",
|
|
||||||
"skill.timescale": "Timescale",
|
|
||||||
"skill.atlassian": "Atlassian",
|
|
||||||
|
|
||||||
|
|
||||||
"time.dur-format": "a duré {duration}",
|
|
||||||
"time.cur-format": "depuis {duration}",
|
|
||||||
"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",
|
|
||||||
"project.username": "Adrien Marquès",
|
|
||||||
|
|
||||||
"end": ""
|
|
||||||
}
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
export default {
|
||||||
|
'home.title': 'DÉVELOPPEUR FREELANCE',
|
||||||
|
'home.line1': 'Hello, je suis développeur freelance !',
|
||||||
|
'home.line2-1': 'J\'ai développé ce site afin de vous permettre de',
|
||||||
|
'home.line2-2': 'parcourir',
|
||||||
|
'home.line2-3': 'mes compétences et projets.',
|
||||||
|
'home.line3': 'J\'ai démarré le dev en 2010. Aujourd\'hui je compte plus de 50 projets à mon actif.',
|
||||||
|
'home.line4': 'Je suis très attaché à fournir à mes clients des projets maintenables afin qu\'ils puissent évoluer à moindre coût (économique et écologique).',
|
||||||
|
'home.line5-1': 'Les technologies qui m\'intéressent actuellement sont le',
|
||||||
|
'home.line5-2': 'et l\'',
|
||||||
|
'home.line5-3': '(Arduino, Raspberry).',
|
||||||
|
|
||||||
|
'timeline.title': 'Chronologie des projets avec',
|
||||||
|
'timeline.title-all': 'Chronologie de tous les projets',
|
||||||
|
'timeline.back': 'Changer de compétence',
|
||||||
|
|
||||||
|
'skills.featured-before': 'Apparaît dans',
|
||||||
|
'skills.featured-after-1': 'projet',
|
||||||
|
'skills.featured-after-n': 'projets',
|
||||||
|
'skills.browse': 'Parcourir les projets',
|
||||||
|
'skills.browse-all': 'Parcourir tous les projets',
|
||||||
|
'skills.guide': 'Vous pouvez sélectionner une compétence afin de parcourir les projets liés. Vous pouvez aussi parcourir tous les projets en ne sélectionnant pas de compétence.',
|
||||||
|
'skills.interest': 'intérêt',
|
||||||
|
'skills.mastery': 'maîtrise',
|
||||||
|
|
||||||
|
'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.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': 'Electronique',
|
||||||
|
'skill.web': 'Web',
|
||||||
|
'skill.rest': 'REST',
|
||||||
|
'skill.crypto': 'Securité/crypto',
|
||||||
|
'skill.imageprocessing': 'Traitement d\'image',
|
||||||
|
'skill.ai': 'Intelligence Artificielle',
|
||||||
|
'skill.deeplearning': 'Deep Learning',
|
||||||
|
'skill.neuralnetwork': 'Réseaux de neuronnes',
|
||||||
|
'skill.opti': 'Optimization',
|
||||||
|
'skill.sockets': 'Sockets',
|
||||||
|
'skill.concurrency': 'Programmation Concurrente',
|
||||||
|
'skill.uiux': 'UI/UX',
|
||||||
|
'skill.inkscape': 'Inkscape',
|
||||||
|
'skill.rnd': 'R&D',
|
||||||
|
'skill.teamlead': 'Chef d\'équipe',
|
||||||
|
'skill.needsanalysis': 'Analyse besoin client',
|
||||||
|
'skill.grpc': 'gRPC',
|
||||||
|
'skill.microservices': 'Micro services',
|
||||||
|
'skill.kubernetes': 'Kubernetes',
|
||||||
|
'skill.scrum': 'SCRUM',
|
||||||
|
'skill.lora': 'LoRa',
|
||||||
|
'skill.architecture': 'Architecture',
|
||||||
|
'skill.chirpstack': 'ChirpStack',
|
||||||
|
'skill.refactor': 'Refactor',
|
||||||
|
'skill.timescale': 'Timescale',
|
||||||
|
'skill.atlassian': 'Atlassian',
|
||||||
|
|
||||||
|
|
||||||
|
'time.dur-format': 'a duré {duration}',
|
||||||
|
'time.cur-format': 'depuis {duration}',
|
||||||
|
'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',
|
||||||
|
'project.username': 'Adrien Marquès',
|
||||||
|
|
||||||
|
'end': ''
|
||||||
|
}
|
|
@ -9,8 +9,8 @@ export const LOCALES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
import en from './en.json';
|
import en from './en';
|
||||||
import fr from './fr.json';
|
import fr from './fr';
|
||||||
|
|
||||||
export const messages = {
|
export const messages = {
|
||||||
[Locales.EN]: en,
|
[Locales.EN]: en,
|
||||||
|
|
Loading…
Reference in New Issue