V1.1
This commit is contained in:
6
public/.htaccess
Normal file
6
public/.htaccess
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /
|
||||||
|
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ /index.html [L]
|
||||||
4
public/robots.txt
Normal file
4
public/robots.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
Disallow: /*?*
|
||||||
|
Sitemap: https://johanleroy.fr/sitemap.xml
|
||||||
32
public/sitemap.xml
Normal file
32
public/sitemap.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
|
||||||
|
<url>
|
||||||
|
<loc>https://johanleroy.fr</loc>
|
||||||
|
<lastmod>2025-04-19</lastmod>
|
||||||
|
<changefreq>weekly</changefreq>
|
||||||
|
<priority>1.0</priority>
|
||||||
|
</url>
|
||||||
|
|
||||||
|
<url>
|
||||||
|
<loc>https://johanleroy.fr/formations</loc>
|
||||||
|
<lastmod>2025-04-19</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.9</priority>
|
||||||
|
</url>
|
||||||
|
|
||||||
|
<url>
|
||||||
|
<loc>https://techos-asso.fr/experience</loc>
|
||||||
|
<lastmod>2025-04-19</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.9</priority>
|
||||||
|
</url>
|
||||||
|
|
||||||
|
<url>
|
||||||
|
<loc>https://techos-asso.fr/projets</loc>
|
||||||
|
<lastmod>2025-04-19</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.9</priority>
|
||||||
|
</url>
|
||||||
|
|
||||||
|
</urlset>
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
<div
|
|
||||||
class="relative flex h-[calc(100vh-2rem)] w-full max-w-[20rem] flex-col rounded-xl bg-white bg-clip-border p-4 text-gray-700 shadow-xl shadow-blue-gray-900/5">
|
|
||||||
<div routerLink="/" class="p-4 mb-2">
|
|
||||||
<h5 class="block cursor-pointer font-sans text-xl antialiased font-semibold leading-snug tracking-normal text-blue-gray-900">
|
|
||||||
YouVideo
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<nav class="flex min-w-[240px] flex-col gap-1 p-2 font-sans text-base font-normal text-blue-gray-700">
|
|
||||||
<div *ngIf="user.id !== 0" class="relative block w-full">
|
|
||||||
<div role="button"
|
|
||||||
class="flex items-center w-full p-0 leading-tight transition-all rounded-lg outline-none bg-blue-gray-50/50 text-start text-blue-gray-700 hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
|
||||||
<button type="button"
|
|
||||||
class="flex items-center justify-between w-full p-3 font-sans text-xl antialiased font-semibold leading-snug text-left transition-colors border-b-0 select-none border-b-blue-gray-100 text-blue-gray-900 hover:text-blue-gray-900">
|
|
||||||
<div class="grid mr-4 place-items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
|
||||||
class="w-5 h-5">
|
|
||||||
<path fill-rule="evenodd"
|
|
||||||
d="M2.25 2.25a.75.75 0 000 1.5H3v10.5a3 3 0 003 3h1.21l-1.172 3.513a.75.75 0 001.424.474l.329-.987h8.418l.33.987a.75.75 0 001.422-.474l-1.17-3.513H18a3 3 0 003-3V3.75h.75a.75.75 0 000-1.5H2.25zm6.04 16.5l.5-1.5h6.42l.5 1.5H8.29zm7.46-12a.75.75 0 00-1.5 0v6a.75.75 0 001.5 0v-6zm-3 2.25a.75.75 0 00-1.5 0v3.75a.75.75 0 001.5 0V9zm-3 2.25a.75.75 0 00-1.5 0v1.5a.75.75 0 001.5 0v-1.5z"
|
|
||||||
clip-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<p class="block mr-auto font-sans text-base antialiased font-normal leading-relaxed text-blue-gray-900">
|
|
||||||
Ma bibliothèque
|
|
||||||
</p>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="overflow-hidden">
|
|
||||||
<div class="block w-full py-1 font-sans text-sm antialiased font-light leading-normal text-gray-700">
|
|
||||||
<nav class="flex min-w-[240px] flex-col gap-1 p-0 font-sans text-base font-normal text-blue-gray-700">
|
|
||||||
<div role="button"
|
|
||||||
class="flex items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
|
||||||
<div class="grid mr-4 place-items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
|
|
||||||
stroke="currentColor" aria-hidden="true" class="w-5 h-3">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
Mes vidéos
|
|
||||||
</div>
|
|
||||||
<div role="button"
|
|
||||||
class="flex items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
|
||||||
<div class="grid mr-4 place-items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
|
|
||||||
stroke="currentColor" aria-hidden="true" class="w-5 h-3">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
Mes playlists
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="user.id !== 0" routerLink="/login" role="button"
|
|
||||||
class="flex cursor-pointer items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
|
||||||
<div class="grid mr-4 place-items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
|
||||||
class="w-5 h-5">
|
|
||||||
<path fill-rule="evenodd"
|
|
||||||
d="M18.685 19.097A9.723 9.723 0 0021.75 12c0-5.385-4.365-9.75-9.75-9.75S2.25 6.615 2.25 12a9.723 9.723 0 003.065 7.097A9.716 9.716 0 0012 21.75a9.716 9.716 0 006.685-2.653zm-12.54-1.285A7.486 7.486 0 0112 15a7.486 7.486 0 015.855 2.812A8.224 8.224 0 0112 20.25a8.224 8.224 0 01-5.855-2.438zM15.75 9a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
|
|
||||||
clip-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
Connexion/Inscription
|
|
||||||
</div>
|
|
||||||
<div *ngIf="user.id !== 0" routerLink="/p" role="button"
|
|
||||||
class="flex cursor-pointer items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
|
||||||
<div class="grid mr-4 place-items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
|
||||||
class="w-5 h-5">
|
|
||||||
<path fill-rule="evenodd"
|
|
||||||
d="M18.685 19.097A9.723 9.723 0 0021.75 12c0-5.385-4.365-9.75-9.75-9.75S2.25 6.615 2.25 12a9.723 9.723 0 003.065 7.097A9.716 9.716 0 0012 21.75a9.716 9.716 0 006.685-2.653zm-12.54-1.285A7.486 7.486 0 0112 15a7.486 7.486 0 015.855 2.812A8.224 8.224 0 0112 20.25a8.224 8.224 0 01-5.855-2.438zM15.75 9a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
|
|
||||||
clip-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
Profile
|
|
||||||
</div>
|
|
||||||
<div *ngIf="user.id !== 0" (click)="logout()" role="button"
|
|
||||||
class="flex cursor-pointer items-center w-full p-3 leading-tight transition-all rounded-lg outline-none text-start hover:bg-blue-gray-50 hover:bg-opacity-80 hover:text-blue-gray-900 focus:bg-blue-gray-50 focus:bg-opacity-80 focus:text-blue-gray-900 active:bg-blue-gray-50 active:bg-opacity-80 active:text-blue-gray-900">
|
|
||||||
<div class="grid mr-4 place-items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"
|
|
||||||
class="w-5 h-5">
|
|
||||||
<path fill-rule="evenodd"
|
|
||||||
d="M12 2.25a.75.75 0 01.75.75v9a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM6.166 5.106a.75.75 0 010 1.06 8.25 8.25 0 1011.668 0 .75.75 0 111.06-1.06c3.808 3.807 3.808 9.98 0 13.788-3.807 3.808-9.98 3.808-13.788 0-3.808-3.807-3.808-9.98 0-13.788a.75.75 0 011.06 0z"
|
|
||||||
clip-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
Déconnexion
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {AuthService} from '../../_services/auth.service';
|
|
||||||
import {Users} from '../../_models/users';
|
|
||||||
import {catchError, of} from 'rxjs';
|
|
||||||
import {NgIf} from '@angular/common';
|
|
||||||
import {Router, RouterLink} from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-sidbar',
|
|
||||||
imports: [
|
|
||||||
NgIf,
|
|
||||||
RouterLink
|
|
||||||
],
|
|
||||||
templateUrl: './sidbar.component.html',
|
|
||||||
styleUrl: './sidbar.component.css'
|
|
||||||
})
|
|
||||||
export class SidbarComponent implements OnInit {
|
|
||||||
|
|
||||||
user: Users = { id: 0, email: '', firstname: '', lastname: '', password_hash: '', updated_at: new Date(), created_at: new Date() };
|
|
||||||
|
|
||||||
constructor(private authService: AuthService, private router: Router) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.checkAuthAndLoadUser();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAuthAndLoadUser(): void {
|
|
||||||
this.authService.isAuthenticated().subscribe(isAuthenticated => {
|
|
||||||
if (isAuthenticated) {
|
|
||||||
this.loadUsers();
|
|
||||||
} else {
|
|
||||||
this.user = { id: 0, email: '', firstname: '', lastname: '', password_hash: '', updated_at: new Date(), created_at: new Date() };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadUsers(): void {
|
|
||||||
this.authService.getProfil().pipe(
|
|
||||||
catchError(error => {
|
|
||||||
console.error('Erreur lors du chargement du profil:', error);
|
|
||||||
return of(null);
|
|
||||||
})
|
|
||||||
).subscribe(users => {
|
|
||||||
if (users) {
|
|
||||||
console.log(users);
|
|
||||||
this.user = users;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
logout(): void {
|
|
||||||
this.authService.logout().subscribe({
|
|
||||||
next: () => {
|
|
||||||
this.router.navigate(['/']);
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.error('Logout failed:', err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
8
src/app/_models/seo.ts
Normal file
8
src/app/_models/seo.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export interface SEOConfig {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
keywords?: string;
|
||||||
|
ogTitle?: string;
|
||||||
|
ogDescription?: string;
|
||||||
|
ogImage?: string;
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
export interface Users {
|
|
||||||
id: number;
|
|
||||||
email: string;
|
|
||||||
firstname: string;
|
|
||||||
lastname: string;
|
|
||||||
password_hash: string;
|
|
||||||
updated_at: Date;
|
|
||||||
created_at: Date;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
export interface Videos {
|
|
||||||
data: Video[];
|
|
||||||
}
|
|
||||||
export interface Video {
|
|
||||||
id: number;
|
|
||||||
user_id: number;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
link_miniature: string;
|
|
||||||
link_video: string;
|
|
||||||
created_at: Date;
|
|
||||||
updated_at: Date;
|
|
||||||
}
|
|
||||||
43
src/app/_services/seo.service.ts
Normal file
43
src/app/_services/seo.service.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import {inject, Injectable} from '@angular/core';
|
||||||
|
import {Meta, Title} from '@angular/platform-browser';
|
||||||
|
import {SEOConfig} from '../_models/seo';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class SeoService {
|
||||||
|
|
||||||
|
private meta = inject(Meta);
|
||||||
|
private title = inject(Title);
|
||||||
|
|
||||||
|
updateSEOMetaTags(config: SEOConfig) {
|
||||||
|
// Mise à jour du titre
|
||||||
|
this.title.setTitle(config.title);
|
||||||
|
|
||||||
|
// Mise à jour des meta tags standards
|
||||||
|
this.meta.updateTag({ name: 'description', content: config.description });
|
||||||
|
if (config.keywords) {
|
||||||
|
this.meta.updateTag({ name: 'keywords', content: config.keywords });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mise à jour des meta tags Open Graph
|
||||||
|
this.meta.updateTag({ property: 'og:title', content: config.ogTitle || config.title });
|
||||||
|
this.meta.updateTag({ property: 'og:description', content: config.ogDescription || config.description });
|
||||||
|
if (config.ogImage) {
|
||||||
|
this.meta.updateTag({ property: 'og:image', content: config.ogImage });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autres meta tags importants
|
||||||
|
this.meta.updateTag({ name: 'robots', content: 'index,follow' });
|
||||||
|
this.meta.updateTag({ name: 'viewport', content: 'width=device-width, initial-scale=1' });
|
||||||
|
}
|
||||||
|
|
||||||
|
createCanonicalLink(url?: string) {
|
||||||
|
const canURL = url || document.URL;
|
||||||
|
const link: HTMLLinkElement = document.createElement('link');
|
||||||
|
link.setAttribute('rel', 'canonical');
|
||||||
|
link.setAttribute('href', canURL);
|
||||||
|
document.head.appendChild(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {SeoService} from '../../../_services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-experience',
|
selector: 'app-experience',
|
||||||
@@ -6,6 +7,18 @@ import { Component } from '@angular/core';
|
|||||||
templateUrl: './experience.component.html',
|
templateUrl: './experience.component.html',
|
||||||
styleUrl: './experience.component.css'
|
styleUrl: './experience.component.css'
|
||||||
})
|
})
|
||||||
export class ExperienceComponent {
|
export class ExperienceComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(private seoService: SeoService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.seoService.updateSEOMetaTags({
|
||||||
|
title: 'Mes expériences - Portfolio',
|
||||||
|
description: 'Découvrez mes expériences',
|
||||||
|
keywords: 'johanleroy, johan, leroy, développeur, portfolio, johan leroy développeur, johan leroy portfolio, johan leroy dev web, johan leroy angular, johan leroy express, développeur web, développeur Angular, développeur Express.js, développeur fullstack, développeur JavaScript, développeur TypeScript, développeur Node.js, développeur REST API, développeur tailwind css, développeur MariaDB, développeur SQL, créer un site web, développeur freelance, portfolio développeur web, expert Angular, développeur application web, intégrateur tailwind, développeur web, freelance développeur\n',
|
||||||
|
ogImage: 'https://johanleroy.fr/favicon.ico'
|
||||||
|
});
|
||||||
|
this.seoService.createCanonicalLink();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {SeoService} from '../../../_services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-formations',
|
selector: 'app-formations',
|
||||||
@@ -6,6 +7,18 @@ import { Component } from '@angular/core';
|
|||||||
templateUrl: './formations.component.html',
|
templateUrl: './formations.component.html',
|
||||||
styleUrl: './formations.component.css'
|
styleUrl: './formations.component.css'
|
||||||
})
|
})
|
||||||
export class FormationsComponent {
|
export class FormationsComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(private seoService: SeoService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.seoService.updateSEOMetaTags({
|
||||||
|
title: 'Mes formations - Portfolio',
|
||||||
|
description: 'Découvrez mes formations',
|
||||||
|
keywords: 'johanleroy, johan, leroy, développeur, portfolio, johan leroy développeur, johan leroy portfolio, johan leroy dev web, johan leroy angular, johan leroy express, développeur web, développeur Angular, développeur Express.js, développeur fullstack, développeur JavaScript, développeur TypeScript, développeur Node.js, développeur REST API, développeur tailwind css, développeur MariaDB, développeur SQL, créer un site web, développeur freelance, portfolio développeur web, expert Angular, développeur application web, intégrateur tailwind, développeur web, freelance développeur\n',
|
||||||
|
ogImage: 'https://johanleroy.fr/favicon.ico'
|
||||||
|
});
|
||||||
|
this.seoService.createCanonicalLink();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {RouterLink} from '@angular/router';
|
import {RouterLink} from '@angular/router';
|
||||||
|
import {SeoService} from '../../../_services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@@ -9,6 +10,18 @@ import {RouterLink} from '@angular/router';
|
|||||||
templateUrl: './home.component.html',
|
templateUrl: './home.component.html',
|
||||||
styleUrl: './home.component.css'
|
styleUrl: './home.component.css'
|
||||||
})
|
})
|
||||||
export class HomeComponent {
|
export class HomeComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(private seoService: SeoService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.seoService.updateSEOMetaTags({
|
||||||
|
title: 'Johan Leroy - Portfolio',
|
||||||
|
description: 'Découvrez mon portfolio',
|
||||||
|
keywords: 'johanleroy, johan, leroy, développeur, portfolio, johan leroy développeur, johan leroy portfolio, johan leroy dev web, johan leroy angular, johan leroy express, développeur web, développeur Angular, développeur Express.js, développeur fullstack, développeur JavaScript, développeur TypeScript, développeur Node.js, développeur REST API, développeur tailwind css, développeur MariaDB, développeur SQL, créer un site web, développeur freelance, portfolio développeur web, expert Angular, développeur application web, intégrateur tailwind, développeur web, freelance développeur\n',
|
||||||
|
ogImage: 'https://johanleroy.fr/favicon.ico'
|
||||||
|
});
|
||||||
|
this.seoService.createCanonicalLink();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {SeoService} from '../../../_services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-projets',
|
selector: 'app-projets',
|
||||||
@@ -6,6 +7,18 @@ import { Component } from '@angular/core';
|
|||||||
templateUrl: './projets.component.html',
|
templateUrl: './projets.component.html',
|
||||||
styleUrl: './projets.component.css'
|
styleUrl: './projets.component.css'
|
||||||
})
|
})
|
||||||
export class ProjetsComponent {
|
export class ProjetsComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(private seoService: SeoService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.seoService.updateSEOMetaTags({
|
||||||
|
title: 'Mes projets - Portfolio',
|
||||||
|
description: 'Découvrez mes projets',
|
||||||
|
keywords: 'johanleroy, johan, leroy, développeur, portfolio, johan leroy développeur, johan leroy portfolio, johan leroy dev web, johan leroy angular, johan leroy express, développeur web, développeur Angular, développeur Express.js, développeur fullstack, développeur JavaScript, développeur TypeScript, développeur Node.js, développeur REST API, développeur tailwind css, développeur MariaDB, développeur SQL, créer un site web, développeur freelance, portfolio développeur web, expert Angular, développeur application web, intégrateur tailwind, développeur web, freelance développeur\n',
|
||||||
|
ogImage: 'https://johanleroy.fr/favicon.ico'
|
||||||
|
});
|
||||||
|
this.seoService.createCanonicalLink();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user