diff --git a/docker-compose-development.rendertron.yml b/docker-compose-development.rendertron.yml new file mode 100644 index 0000000000000000000000000000000000000000..02ada2ac629544409e59e94487e22106586a61b5 --- /dev/null +++ b/docker-compose-development.rendertron.yml @@ -0,0 +1,38 @@ +version: "3.7" + +services: + rendertron: + build: + context: ./docker/dev/ + dockerfile: Dockerfile-rendertron + networks: + - default + - grandlyon + labels: + - "traefik.frontend.rule=Host:rendertron.data.grandlyon.docker" + - "traefik.port=8083" + - "traefik.protocol=http" + - "traefik.docker.network=grandlyon" + + proxy: + build: + context: ./docker/dev/ + dockerfile: Dockerfile-nginx + volumes: + - ./docker/dev/nginx-development-proxy.conf:/etc/nginx/conf.d/default.conf + labels: + - "traefik.frontend.rule=Host:data.grandlyon.docker" + - "traefik.port=80" + - "traefik.protocol=http" + - "traefik.docker.network=grandlyon" + networks: + default: + aliases: + - data.grandlyon.docker + grandlyon: + + +networks: + grandlyon: + external: true + diff --git a/docker/dev/Dockerfile-nginx b/docker/dev/Dockerfile-nginx new file mode 100644 index 0000000000000000000000000000000000000000..4eb4435b4f47c608352f56da2b5a001e5ceb975a --- /dev/null +++ b/docker/dev/Dockerfile-nginx @@ -0,0 +1,9 @@ +FROM nginx + +RUN apt-get update + +RUN apt-get --assume-yes install nginx-extras + +RUN rm /etc/nginx/conf.d/* + +RUN ls -l /usr/share/nginx/html diff --git a/docker/dev/Dockerfile-rendertron b/docker/dev/Dockerfile-rendertron new file mode 100644 index 0000000000000000000000000000000000000000..a1ada574c9a499d777d42a5b83c5c9972ebca6b6 --- /dev/null +++ b/docker/dev/Dockerfile-rendertron @@ -0,0 +1 @@ +FROM scandipwa/rendertron diff --git a/docker/dev/nginx-development-proxy.conf b/docker/dev/nginx-development-proxy.conf new file mode 100644 index 0000000000000000000000000000000000000000..6fcd6d52674fac780be0968b8c30a308a05ac1ec --- /dev/null +++ b/docker/dev/nginx-development-proxy.conf @@ -0,0 +1,46 @@ +server { + # staging server is listening on the port 8180 + listen 80; + server_name data.grandlyon.docker proxy; + root /usr/share/nginx/html/; + + error_page 404 /page-404; + + location / { + set $prerender 0; + if ($http_user_agent ~* "googlebot|yahoo|bingbot|baiduspider|yandex|yeti|yodaobot|gigabot|ia_archiver|facebookexternalhit|twitterbot|linkedinbot|developers\.google\.com") { + set $prerender 1; + } + if ($args ~ "_escaped_fragment_|prerender=1") { + set $prerender 1; + } + if ($http_user_agent ~ "Prerender") { + set $prerender 0; + } + + if ($request_uri ~* "gif|png|jpg|pdf|svg|jpeg|css") { + set $prerender 0; + } + + if ($prerender = 1) { + rewrite .* /render/http://$server_name$request_uri break; + proxy_pass http://rendertron:8083; + add_header Access-Control-Allow-Origin *; + } + + if ($prerender = 0) { + proxy_pass http://host.docker.internal:4200; + add_header Access-Control-Allow-Origin *; + } + + if ($request_uri ~* "page-404") { + proxy_pass http://host.docker.internal:4200; + return 404; + } + } + + #location /robots.txt { + # rewrite ^ /fr/robots.txt; + #} + +} diff --git a/package.json b/package.json index cd9805d130d525f5781aad607e7eafdb70fd79c1..0a1ae9899d375b260ff869dcf22b07638734c4b0 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "scripts": { "ng": "ng", "start": "ng serve --proxy-config proxy.conf.json", - "start-aot-fr": "ng serve --configuration=aot-fr", - "start-aot-en": "ng serve --configuration=aot-en", + "start-aot-fr": "ng serve --configuration=aot-fr --disable-host-check", + "start-aot-en": "ng serve --configuration=aot-en --disable-host-check", "build-i18n:dev": "for lang in en fr; do node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration=development-$lang --delete-output-path false; done", "build-i18n:prod": "for lang in en fr; do node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration=production-$lang --delete-output-path false; done", "win-build-i18n:fr": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng build --configuration=development-fr --delete-output-path false", diff --git a/readme.md b/readme.md index 6962d01ff84579ad95b6a36781ced473983b632f..e0aaec1744dc1ed01f541faa6dc123d181ceb110 100644 --- a/readme.md +++ b/readme.md @@ -27,6 +27,17 @@ Using the npm script (which use the Angular CLI): npm run start ``` +### Using with rendertron + +Add 127.0.0.1 data.grandlyon.docker rendertron.data.grandlyon.docker to your host +Run the container with + +```bash +docker-compose -f docker-compose-developement.rendertron.yml up -d +``` + +Start the web application with npm. You can no acces to both app and SSR version through the 2 domains aforesaid. + ### Build the application We defined in the package.json two scripts that can build the application. One that generates an optimized build and the other an unoptimized build. The optimized build takes longer than the normal one. diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index c807ad61a047aa6f9da7108042bd1e807790ce7b..4b238a0f8a7c48c09b4a07cd38180f15958af365 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,8 +1,13 @@ import { NgModule } from '@angular/core'; import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; +import { HomeComponent } from './editorialisation/components'; import { AppRoutes } from './routes'; export const routes: Routes = [ + { + path: '', + component: HomeComponent, + }, { path: '**', redirectTo: AppRoutes.page404.uri, diff --git a/src/app/app.component.ts b/src/app/app.component.ts index e8031ca7f20e688b56f8d6c8fbda081c24875844..330754000933f2cedd9c31712fc48993b90c11fa 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -6,6 +6,8 @@ import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { environment } from '../environments/environment'; import { NavigationHistoryService } from './core/services'; import { AppRoutes } from './routes'; +import { SeoSErvice } from './editorialisation/services'; +import { pageTitles } from '../i18n/traductions'; @Component({ selector: 'app-root', @@ -19,6 +21,7 @@ export class AppComponent implements OnInit { private _activatedRoute: ActivatedRoute, private _titleService: Title, private _angulartics2Piwik: Angulartics2Piwik, + private _seoSErvice: SeoSErvice, ) { this._angulartics2Piwik.startTracking(); } @@ -30,6 +33,7 @@ export class AppComponent implements OnInit { this._navigationHistoryService.add(e['urlAfterRedirects']); }); + // Change the title using the title property passed in the data of each route this._router.events.pipe( filter(event => event instanceof NavigationEnd), @@ -46,9 +50,15 @@ export class AppComponent implements OnInit { } return titles; }), - ).subscribe((titles) => { - const title = titles.join(' - '); - this._titleService.setTitle(title); + ).subscribe((titles): void => { + if (titles.length > 1) { + const title = titles.join(' - '); + this._seoSErvice.setRoutingSEO(title); + } + else { + this._seoSErvice.setRoutingSEO(''); + } + }); } diff --git a/src/app/core/components/main/header/header.component.html b/src/app/core/components/main/header/header.component.html index 628ad64eb46f72181ce0fa3d929f6872a9f24d44..b7306a33299167fe2dd7ff66d26ccc84a0afcf68 100644 --- a/src/app/core/components/main/header/header.component.html +++ b/src/app/core/components/main/header/header.component.html @@ -9,7 +9,7 @@ </div> </div> <div class="navbar-header-item logo-data"> - <a [routerLink]="['/', AppRoutes.home.uri]" *ngIf="!isHomePage"> + <a [routerLink]="['']" *ngIf="!isHomePage"> <img class="logo-data-beta is-hidden-mobile" src="./assets/img/header_logo_data.svg" alt="Return to homepage" i18n-alt="@@header.returnHome"> <img class="is-hidden-tablet" src="./assets/img/header_logo_data_mobile.svg" diff --git a/src/app/core/components/main/side-menu/side-menu.component.html b/src/app/core/components/main/side-menu/side-menu.component.html index e051c972b83c165dee034ec8dbcd365de7603b48..b6103f2c47bdf086a387293d4a72bb6fb62104f1 100644 --- a/src/app/core/components/main/side-menu/side-menu.component.html +++ b/src/app/core/components/main/side-menu/side-menu.component.html @@ -3,7 +3,7 @@ <nav class="menu-list"> <ul class="menu-list"> <li> - <a [routerLink]="['/', AppRoutes.home.uri]" routerLinkActive="active-link" + <a [routerLink]="['/']" routerLinkActive="active-link" [routerLinkActiveOptions]="{ exact: true }" [tabIndex]="isOpened ? 0 : -1"> <div class="icon-item"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23"> @@ -16,14 +16,26 @@ </a> </li> <li> - <a [routerLink]="['/', AppRoutes.research.uri]" routerLinkActive="active-link" [tabIndex]="isOpened ? 0 : -1"> + <a [routerLink]="['/', AppRoutes.datasets.uri]" routerLinkActive="active-link" [tabIndex]="isOpened ? 0 : -1"> <div class="icon-item"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23"> <path class="main" fill-rule="evenodd" d="M18.1 10.1a8 8 0 1 1-8-8 8 8 0 0 1 8 8zm-1.9 6.7a9.2 9.2 0 0 1-6.1 2.3 9 9 0 1 1 9-9 9 9 0 0 1-2.2 6l5 4.8a.5.5 0 0 1 0 .7.6.6 0 0 1-.8 0z" /> </svg> </div> - <span i18n="@@menu.research" class="label-menu">Research</span> + <span i18n="@@menu.datasets" class="label-menu">Datasets</span> + </a> + </li> + <li> + <a [routerLink]="['/', AppRoutes.news.uri]" routerLinkActive="active-link" [tabIndex]="isOpened ? 0 : -1"> + <div class="icon-item"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23"> + <path id="picto_x5F_documentation" + d="M19 6.9l-5-4.7c-.4-.5-.9-.7-1.5-.7h-6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V8.2c0-.4-.2-.9-.5-1.3zm-5.7-4l4.9 4.6H14c-.6 0-1-.4-1-1V2.7c.1 0 .2.1.3.2zm4.2 17.6h-11c-.6 0-1-.4-1-1v-16c0-.6.4-1 1-1H12v4c0 1.1.9 2 2 2h4.5v11c0 .6-.4 1-1 1z" + class="main" /> + </svg> + </div> + <span i18n="@@menu.news" class="label-menu">News</span> </a> </li> <li *ngIf="APP_CONFIG.theFunctionalitiesInterruptor.partners"> diff --git a/src/app/core/components/main/side-menu/side-menu.component.scss b/src/app/core/components/main/side-menu/side-menu.component.scss index a65d7b2078870035078e24706e21178914fa541c..65de302c8341068bf0b42d8d9bebf80dabd270cb 100644 --- a/src/app/core/components/main/side-menu/side-menu.component.scss +++ b/src/app/core/components/main/side-menu/side-menu.component.scss @@ -7,6 +7,7 @@ display: flex; flex-direction: column; justify-content: space-between; + overflow-y: auto; @media screen and (max-width: $tablet) { overflow: scroll; diff --git a/src/app/core/components/page-not-found/page-not-found.component.html b/src/app/core/components/page-not-found/page-not-found.component.html index a40befeb665ad1559ed3adf0b779edfd34965fc2..4c9e09700e3ab60c9830fa3755ba1eb9e019c0d1 100644 --- a/src/app/core/components/page-not-found/page-not-found.component.html +++ b/src/app/core/components/page-not-found/page-not-found.component.html @@ -8,4 +8,4 @@ i18n="@@page404.backBtnText">Back to home page</a> </div> -</div> \ No newline at end of file +</div> diff --git a/src/app/core/components/page-not-found/page-not-found.component.ts b/src/app/core/components/page-not-found/page-not-found.component.ts index c9f44892318596db4f10e1d18f0c8aa7a71affd7..f22055fca35bad48750e0f7cb3fe22d7efb86c4d 100644 --- a/src/app/core/components/page-not-found/page-not-found.component.ts +++ b/src/app/core/components/page-not-found/page-not-found.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { AppRoutes } from '../../../routes'; +import { isRentertron } from '../../../shared/variables'; @Component({ selector: 'app-page-not-found', @@ -13,6 +14,10 @@ export class PageNotFoundComponent implements OnInit { constructor() { } ngOnInit() { + if (isRentertron) { + window.location.href = 'page-404'; + } + } } diff --git a/src/app/core/core-routing.module.ts b/src/app/core/core-routing.module.ts index 7374399aad47ecc2211aae684f55a4be7b146e89..06e717a63a651167e8a3cb6973d9c21eaa5f204d 100644 --- a/src/app/core/core-routing.module.ts +++ b/src/app/core/core-routing.module.ts @@ -1,5 +1,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; +import { HomeComponent } from '../editorialisation/components'; import { AppRoutes } from '../routes'; import { ContactComponent } from './components'; import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component'; @@ -7,8 +8,7 @@ import { PageNotFoundComponent } from './components/page-not-found/page-not-foun export const routes: Routes = [ { path: '', - redirectTo: AppRoutes.home.uri, - pathMatch: 'full', + component: HomeComponent, }, { path: AppRoutes.page404.uri, diff --git a/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html b/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html index 1a5c67bce00d31722ea1607e1c0658ef245c9ab3..e58f18175048ae8c4f713d1082039a51f92a89ec 100644 --- a/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html +++ b/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.html @@ -3,122 +3,36 @@ <app-page-header [pageInfo]="pageHeaderInfo" [customGoToPreviousPage]="goToPreviousPage"></app-page-header> </div> - <div class="tabulations"> + <div class="tabulations" > <ul class="navigation-tabs"> - <li [routerLinkActive]="'is-active'" *ngIf="hasTable || hasMap"> - <a (click)="setPosition()" [routerLink]="[AppRoutes.data.uri]" class="tab-link"> - <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38 32" aria-hidden="true"> - <path class="primary" - d="M19 0L4.5 6.4v19.4L19 32l14.5-6.4V6.4L19 0zm13.5 24.9l-13 5.7-.5.3-13.5-5.8v-18l13.5-6 13.1 5.8L19 13l.5.2v.6l13-6.1v17.2z" /> - <path class="secondary" d="M19 30.9l.5-.2V13.2L5.9 6.9l-.4.2v.7l13 6.1v16.8z" /> - </svg> - <div class="tab-text-wrapper"> - <div> - <span class="tab-title" i18n="@@dataset.detail.data">Data</span> - </div> - <div> - <span class="tab-subtitle" i18n="@@dataset.detail.lines">{{ datasetDataNumber }} lines</span> - </div> - </div> + <li [routerLinkActive]="'is-active'"> + <a (click)="setPosition()" [routerLink]="[AppRoutes.info.uri]" class="tab-link" *ngIf="!isRendertron; else infoTab"> + <ng-template *ngTemplateOutlet="infoTab"></ng-template> </a> </li> - <li [routerLinkActive]="'is-active'"> - <a (click)="setPosition()" [routerLink]="[AppRoutes.info.uri]" class="tab-link"> - <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 37" aria-hidden="true"> - <g id="picto_x5F_info"> - <path d="M19 15.6c.3 0 .5.2.5.6V25c0 .3-.2.6-.5.6s-.5-.2-.5-.6v-8.9c0-.3.2-.5.5-.5z" class="secondary" /> - <circle cx="19" cy="12" r=".5" class="secondary" /> - <path - d="M19 2.5c8.5 0 15.5 7 15.5 15.5s-7 15.5-15.5 15.5S3.5 26.5 3.5 18 10.5 2.5 19 2.5m0-1C9.9 1.5 2.5 8.9 2.5 18S9.9 34.5 19 34.5 35.5 27.1 35.5 18 28.1 1.5 19 1.5z" - class="primary" /> - </g> - </svg> - - <div class="tab-text-wrapper"> - <div> - <span class="tab-title tab-title-long" i18n="@@dataset.detail.infoTab">Information</span> - <span class="tab-title tab-title-short">Info</span> - </div> - <div> - <span class="tab-subtitle" [title]="datasetLicense"> - {{ datasetLicense }} - </span> - </div> - </div> + <li [routerLinkActive]="'is-active'" *ngIf="hasTable || hasMap"> + <a (click)="setPosition()" [routerLink]="[AppRoutes.data.uri]" class="tab-link" *ngIf="!isRendertron; else dataTab"> + <ng-template *ngTemplateOutlet="dataTab"></ng-template> </a> </li> <li [routerLinkActive]="'is-active'" *ngIf="datasetFormatsList"> - <a (click)="setPosition()" [routerLink]="[AppRoutes.downloads.uri]" class="tab-link"> - <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" data-name="Calque 1" viewBox="0 0 38 32" aria-hidden="true"> - <path class="primary" - d="M32.515 30H4.5a.5.5 0 01-.5-.5v-7.485a.5.5 0 011 0V29h27.015v-6.985a.5.5 0 011 0V29.5a.5.5 0 01-.5.5z" /> - <path class="secondary" - d="M26.771 14.024a.5.5 0 00-.708 0l-7.056 7.057V2.7a.5.5 0 00-1 0v18.381l-7.056-7.057a.5.5 0 00-.707.707l7.91 7.911a.5.5 0 00.707 0l7.91-7.911a.5.5 0 000-.707z" /> - </svg> - <div class="tab-text-wrapper"> - <div> - <span class="tab-title tab-title-long" i18n="@@dataset.detail.downloads">Downloads</span> - <span class="tab-title tab-title-short" i18n="@@dataset.detail.downloads">Downloads</span> - </div> - <div> - <span class="tab-subtitle">{{ datasetFormatsList }}</span> - </div> - </div> + <a (click)="setPosition()" [routerLink]="[AppRoutes.downloads.uri]" class="tab-link" *ngIf="!isRendertron; else dlTab"> + <ng-template *ngTemplateOutlet="dlTab"></ng-template> </a> </li> <li [routerLinkActive]="'is-active'" *ngIf="datasetServicesList.length > 0"> - <a (click)="setPosition()" [routerLink]="[AppRoutes.resources.uri]" class="tab-link"> - <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" data-name="Calque 1" viewBox="0 0 38 32" aria-hidden="true"> - <path class="secondary" - d="M12.841 22.076l-8.889-5.484 8.889-5.485a.5.5 0 10-.526-.85l-9.578 5.91-.011.01a.616.616 0 00-.075.07.478.478 0 00-.065.07s-.009.007-.012.012a.489.489 0 00-.026.073.411.411 0 00-.035.094.466.466 0 000 .1.55.55 0 000 .091.456.456 0 00.038.1.412.412 0 00.024.067l.01.01a.5.5 0 00.153.154l9.578 5.91a.5.5 0 00.526-.852z" /> - <path class="primary" - d="M35.491 16.594a.46.46 0 000-.1.418.418 0 00-.035-.095.477.477 0 00-.026-.072s-.009-.007-.012-.012a.478.478 0 00-.065-.07.546.546 0 00-.075-.07l-.011-.01-9.578-5.91a.5.5 0 10-.526.85l8.889 5.485-8.889 5.484a.5.5 0 00.526.852l9.578-5.91a.5.5 0 00.153-.154l.01-.01a.54.54 0 00.025-.067.509.509 0 00.037-.1.562.562 0 00-.001-.091zM15.53 28.907a.526.526 0 01-.14-.02.5.5 0 01-.339-.62L21.99 4.6a.5.5 0 01.959.281L16.01 28.548a.5.5 0 01-.48.359z" /> - </svg> - <div class="tab-text-wrapper"> - <div> - <span class="tab-title tab-title-long" i18n="@@dataset.detail.api">API</span> - <span class="tab-title tab-title-short">API</span> - </div> - <div> - <span class="tab-subtitle">{{ datasetServicesList }}</span> - </div> - </div> + <a (click)="setPosition()" [routerLink]="[AppRoutes.resources.uri]" class="tab-link" *ngIf="!isRendertron; else apiTab"> + <ng-template *ngTemplateOutlet="apiTab"></ng-template> </a> </li> <li [routerLinkActive]="'is-active'" *ngIf="otherResourceList && !datasetFormatsList"> - <a (click)="setPosition()" [routerLink]="[AppRoutes.otherResources.uri]" class="tab-link"> - <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" data-name="Calque 1" viewBox="0 0 38 32" aria-hidden="true"> - <path class="secondary" - d="M12.841 22.076l-8.889-5.484 8.889-5.485a.5.5 0 10-.526-.85l-9.578 5.91-.011.01a.616.616 0 00-.075.07.478.478 0 00-.065.07s-.009.007-.012.012a.489.489 0 00-.026.073.411.411 0 00-.035.094.466.466 0 000 .1.55.55 0 000 .091.456.456 0 00.038.1.412.412 0 00.024.067l.01.01a.5.5 0 00.153.154l9.578 5.91a.5.5 0 00.526-.852z" /> - <path class="primary" - d="M35.491 16.594a.46.46 0 000-.1.418.418 0 00-.035-.095.477.477 0 00-.026-.072s-.009-.007-.012-.012a.478.478 0 00-.065-.07.546.546 0 00-.075-.07l-.011-.01-9.578-5.91a.5.5 0 10-.526.85l8.889 5.485-8.889 5.484a.5.5 0 00.526.852l9.578-5.91a.5.5 0 00.153-.154l.01-.01a.54.54 0 00.025-.067.509.509 0 00.037-.1.562.562 0 00-.001-.091zM15.53 28.907a.526.526 0 01-.14-.02.5.5 0 01-.339-.62L21.99 4.6a.5.5 0 01.959.281L16.01 28.548a.5.5 0 01-.48.359z" /> - </svg> - <div class="tab-text-wrapper"> - <div> - <span class="tab-title tab-title-long" i18n="@@dataset.detail.resources">Ressources</span> - <span class="tab-title tab-title-short" i18n="@@dataset.detail.resources">Ressources</span> - </div> - <div> - <span class="tab-subtitle">{{ datasetFormatsList }}</span> - </div> - </div> + <a (click)="setPosition()" [routerLink]="[AppRoutes.otherResources.uri]" class="tab-link" *ngIf="!isRendertron; else resTab"> + <ng-template *ngTemplateOutlet="resTab"></ng-template> </a> </li> <li [routerLinkActive]="'is-active'"> - <a (click)="setPosition()" [routerLink]="[AppRoutes.dataReuses.uri]" class="tab-link"> - <svg class="tab-icon" viewBox="0 0 38 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> - <path class="primary" fill-rule="evenodd" clip-rule="evenodd" d="M5 6.286L19.455 0 33.91 6.285V25.14l-14.455 6.284L5 25.14V6.286zm27.59.516l-6.484-2.82.002.005-5.362 2.264-1.229-.567 5.328-2.25-5.39-2.344-5.423 2.358 5.4 2.218-1.24.572-5.33-2.189.046-.112-6.59 2.866 5.494 2.38-.527.244v.619L6 7.754v7.874l5.285 2.485v1.055l1 .423v7.626l6.541 2.844v-7.703l.63.267.37-.157v7.7h-.007l.006.005 6.543-2.845V19.7l1.257-.532v-1.086l5.285-2.46V7.753l-5.285 2.286v-.613l-.532-.246 5.497-2.378zm.32 9.923l-5.542 2.58v7.588l5.542-2.41v-7.758zM11.285 26.782v-7.564L6 16.733v7.752l5.285 2.297z" fill="#464A57"/> - <path class="secondary" fill-rule="evenodd" clip-rule="evenodd" d="M11.285 19.17V9.427l8.17-3.771 8.17 3.77v9.742l-8.17 3.457-8.17-3.457v.002zm1.75-9.45l6.42-2.962 6.45 2.976-6.274 2.836h-.349l-6.247-2.85zm-.75.758v8.029l6.541 2.767V13.46l-6.54-2.983zm7.541 10.905l6.8-2.877v-8l-6.8 3.073v7.804z" fill="#DA322F"/> - </svg> - <div class="tab-text-wrapper"> - <div> - <span class="tab-title tab-title-long" i18n="@@dataset.detail.reuse">Reuse</span> - <span class="tab-title tab-title-short" i18n="@@dataset.detail.reuse">Reuse</span> - </div> - <div> - <span class="tab-subtitle">{{reusesTypes}}</span> - </div> - </div> + <a (click)="setPosition()" [routerLink]="[AppRoutes.dataReuses.uri]" class="tab-link" *ngIf="!isRendertron; else reuseTab"> + <ng-template *ngTemplateOutlet="reuseTab"></ng-template> </a> </li> </ul> @@ -127,3 +41,112 @@ <router-outlet></router-outlet> </div> </div> + +<ng-template #infoTab> + <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 37" aria-hidden="true"> + <g id="picto_x5F_info"> + <path d="M19 15.6c.3 0 .5.2.5.6V25c0 .3-.2.6-.5.6s-.5-.2-.5-.6v-8.9c0-.3.2-.5.5-.5z" class="secondary" /> + <circle cx="19" cy="12" r=".5" class="secondary" /> + <path + d="M19 2.5c8.5 0 15.5 7 15.5 15.5s-7 15.5-15.5 15.5S3.5 26.5 3.5 18 10.5 2.5 19 2.5m0-1C9.9 1.5 2.5 8.9 2.5 18S9.9 34.5 19 34.5 35.5 27.1 35.5 18 28.1 1.5 19 1.5z" + class="primary" /> + </g> + </svg> + <div class="tab-text-wrapper"> + <div> + <span class="tab-title tab-title-long" i18n="@@dataset.detail.infoTab">Information</span> + <span class="tab-title tab-title-short">Info</span> + </div> + <div> + <span class="tab-subtitle" [title]="datasetLicense"> + {{ datasetLicense }} + </span> + </div> + </div> +</ng-template> + +<ng-template #dataTab> + <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38 32" aria-hidden="true"> + <path class="primary" + d="M19 0L4.5 6.4v19.4L19 32l14.5-6.4V6.4L19 0zm13.5 24.9l-13 5.7-.5.3-13.5-5.8v-18l13.5-6 13.1 5.8L19 13l.5.2v.6l13-6.1v17.2z" /> + <path class="secondary" d="M19 30.9l.5-.2V13.2L5.9 6.9l-.4.2v.7l13 6.1v16.8z" /> + </svg> + <div class="tab-text-wrapper"> + <div> + <span class="tab-title" i18n="@@dataset.detail.data">Data</span> + </div> + <div> + <span class="tab-subtitle" i18n="@@dataset.detail.lines">{{ datasetDataNumber }} lines</span> + </div> + </div> +</ng-template> + +<ng-template #dlTab> + <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" data-name="Calque 1" viewBox="0 0 38 32" aria-hidden="true"> + <path class="primary" + d="M32.515 30H4.5a.5.5 0 01-.5-.5v-7.485a.5.5 0 011 0V29h27.015v-6.985a.5.5 0 011 0V29.5a.5.5 0 01-.5.5z" /> + <path class="secondary" + d="M26.771 14.024a.5.5 0 00-.708 0l-7.056 7.057V2.7a.5.5 0 00-1 0v18.381l-7.056-7.057a.5.5 0 00-.707.707l7.91 7.911a.5.5 0 00.707 0l7.91-7.911a.5.5 0 000-.707z" /> + </svg> + <div class="tab-text-wrapper"> + <div> + <span class="tab-title tab-title-long" i18n="@@dataset.detail.downloads">Downloads</span> + <span class="tab-title tab-title-short" i18n="@@dataset.detail.downloads">Downloads</span> + </div> + <div> + <span class="tab-subtitle">{{ datasetFormatsList }}</span> + </div> + </div> +</ng-template> + +<ng-template #apiTab> + <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" data-name="Calque 1" viewBox="0 0 38 32" aria-hidden="true"> + <path class="secondary" + d="M12.841 22.076l-8.889-5.484 8.889-5.485a.5.5 0 10-.526-.85l-9.578 5.91-.011.01a.616.616 0 00-.075.07.478.478 0 00-.065.07s-.009.007-.012.012a.489.489 0 00-.026.073.411.411 0 00-.035.094.466.466 0 000 .1.55.55 0 000 .091.456.456 0 00.038.1.412.412 0 00.024.067l.01.01a.5.5 0 00.153.154l9.578 5.91a.5.5 0 00.526-.852z" /> + <path class="primary" + d="M35.491 16.594a.46.46 0 000-.1.418.418 0 00-.035-.095.477.477 0 00-.026-.072s-.009-.007-.012-.012a.478.478 0 00-.065-.07.546.546 0 00-.075-.07l-.011-.01-9.578-5.91a.5.5 0 10-.526.85l8.889 5.485-8.889 5.484a.5.5 0 00.526.852l9.578-5.91a.5.5 0 00.153-.154l.01-.01a.54.54 0 00.025-.067.509.509 0 00.037-.1.562.562 0 00-.001-.091zM15.53 28.907a.526.526 0 01-.14-.02.5.5 0 01-.339-.62L21.99 4.6a.5.5 0 01.959.281L16.01 28.548a.5.5 0 01-.48.359z" /> + </svg> + <div class="tab-text-wrapper"> + <div> + <span class="tab-title tab-title-long" i18n="@@dataset.detail.api">API</span> + <span class="tab-title tab-title-short">API</span> + </div> + <div> + <span class="tab-subtitle">{{ datasetServicesList }}</span> + </div> + </div> +</ng-template> + +<ng-template #resTab> + <svg class="tab-icon" xmlns="http://www.w3.org/2000/svg" data-name="Calque 1" viewBox="0 0 38 32" aria-hidden="true"> + <path class="secondary" + d="M12.841 22.076l-8.889-5.484 8.889-5.485a.5.5 0 10-.526-.85l-9.578 5.91-.011.01a.616.616 0 00-.075.07.478.478 0 00-.065.07s-.009.007-.012.012a.489.489 0 00-.026.073.411.411 0 00-.035.094.466.466 0 000 .1.55.55 0 000 .091.456.456 0 00.038.1.412.412 0 00.024.067l.01.01a.5.5 0 00.153.154l9.578 5.91a.5.5 0 00.526-.852z" /> + <path class="primary" + d="M35.491 16.594a.46.46 0 000-.1.418.418 0 00-.035-.095.477.477 0 00-.026-.072s-.009-.007-.012-.012a.478.478 0 00-.065-.07.546.546 0 00-.075-.07l-.011-.01-9.578-5.91a.5.5 0 10-.526.85l8.889 5.485-8.889 5.484a.5.5 0 00.526.852l9.578-5.91a.5.5 0 00.153-.154l.01-.01a.54.54 0 00.025-.067.509.509 0 00.037-.1.562.562 0 00-.001-.091zM15.53 28.907a.526.526 0 01-.14-.02.5.5 0 01-.339-.62L21.99 4.6a.5.5 0 01.959.281L16.01 28.548a.5.5 0 01-.48.359z" /> + </svg> + <div class="tab-text-wrapper"> + <div> + <span class="tab-title tab-title-long" i18n="@@dataset.detail.resources">Ressources</span> + <span class="tab-title tab-title-short" i18n="@@dataset.detail.resources">Ressources</span> + </div> + <div> + <span class="tab-subtitle">{{ datasetFormatsList }}</span> + </div> + </div> +</ng-template> + +<ng-template #reuseTab> + <svg class="tab-icon" viewBox="0 0 38 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> + <path class="primary" fill-rule="evenodd" clip-rule="evenodd" d="M5 6.286L19.455 0 33.91 6.285V25.14l-14.455 6.284L5 25.14V6.286zm27.59.516l-6.484-2.82.002.005-5.362 2.264-1.229-.567 5.328-2.25-5.39-2.344-5.423 2.358 5.4 2.218-1.24.572-5.33-2.189.046-.112-6.59 2.866 5.494 2.38-.527.244v.619L6 7.754v7.874l5.285 2.485v1.055l1 .423v7.626l6.541 2.844v-7.703l.63.267.37-.157v7.7h-.007l.006.005 6.543-2.845V19.7l1.257-.532v-1.086l5.285-2.46V7.753l-5.285 2.286v-.613l-.532-.246 5.497-2.378zm.32 9.923l-5.542 2.58v7.588l5.542-2.41v-7.758zM11.285 26.782v-7.564L6 16.733v7.752l5.285 2.297z" fill="#464A57"/> + <path class="secondary" fill-rule="evenodd" clip-rule="evenodd" d="M11.285 19.17V9.427l8.17-3.771 8.17 3.77v9.742l-8.17 3.457-8.17-3.457v.002zm1.75-9.45l6.42-2.962 6.45 2.976-6.274 2.836h-.349l-6.247-2.85zm-.75.758v8.029l6.541 2.767V13.46l-6.54-2.983zm7.541 10.905l6.8-2.877v-8l-6.8 3.073v7.804z" fill="#DA322F"/> + </svg> + <div class="tab-text-wrapper"> + <div> + <span class="tab-title tab-title-long" i18n="@@dataset.detail.reuse">Reuse</span> + <span class="tab-title tab-title-short" i18n="@@dataset.detail.reuse">Reuse</span> + </div> + <div> + <span class="tab-subtitle">{{reusesTypes}}</span> + </div> + </div> +</ng-template> diff --git a/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.ts b/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.ts index 67e9466c2786613b7eafe36d151df74e371475ee..a37b0c61e3f173e3e22b1fe1a617ba7450f02b12 100644 --- a/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.ts +++ b/src/app/dataset-detail/components/dataset-detail/dataset-detail.component.ts @@ -1,5 +1,4 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Meta } from '@angular/platform-browser'; import { ActivatedRoute, Router, Scroll } from '@angular/router'; import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; @@ -9,7 +8,9 @@ import { datatsetDataRepresentationType, geosource, reusesTypes } from '../../.. import { NavigationHistoryService } from '../../../core/services'; import { AppRoutes } from '../../../routes'; import { IPageHeaderInfo, Metadata, typesMetadata } from '../../../shared/models'; +import { isRentertron } from '../../../shared/variables'; import { DatasetDetailService } from '../../services'; +import { SeoSErvice } from '../../../editorialisation/services'; @Component({ @@ -20,6 +21,8 @@ import { DatasetDetailService } from '../../services'; export class DatasetDetailComponent implements OnInit, OnDestroy { AppRoutes = AppRoutes; + isRendertron = isRentertron; + pageHeaderInfo: IPageHeaderInfo = { title: '', shareButtons: { @@ -38,7 +41,7 @@ export class DatasetDetailComponent implements OnInit, OnDestroy { private _router: Router, private _scroller: ViewportScroller, private _navigationHistoryService: NavigationHistoryService, - private _meta: Meta, + private _seoService: SeoSErvice, ) { } ngOnInit() { @@ -55,8 +58,6 @@ export class DatasetDetailComponent implements OnInit, OnDestroy { this._route.params.subscribe((params) => { // Set the title and description for the research page - this._meta.updateTag({ name: 'description', content: this.metadata.abstract }); - this.isLoading = true; this.initDatasetInfo(); }); @@ -221,19 +222,21 @@ export class DatasetDetailComponent implements OnInit, OnDestroy { this.isLoading = false; + this._seoService.setDatasetSEO(this.metadata); + // If a tab (info, data...) is not specified in the url then redirect to the data tab if the dataset // as a table or a map or to the info tab in the failing case if (!this._route.snapshot.firstChild) { - if (this.hasTable || this.hasMap) { + //if (this.hasTable || this.hasMap) { this._router.navigate([ - `/${AppRoutes.datasets.uri}/${this._datasetDetailService.dataset.slug}/${AppRoutes.data.uri}`, + `/${AppRoutes.datasets.uri}/${this._datasetDetailService.dataset.slug}/${AppRoutes.info.uri}`, // tslint:disable-next-line: align ], { queryParamsHandling: 'preserve', replaceUrl: true }); - } else { + /*} else { this._router.navigate([ `/${AppRoutes.datasets.uri}/${this._datasetDetailService.dataset.slug}/${AppRoutes.info.uri}`, ], {replaceUrl: true}); - } + }*/ } else { // Making that the url contains the slug and not the uuid of the dataset this._router.navigate([ @@ -266,7 +269,7 @@ export class DatasetDetailComponent implements OnInit, OnDestroy { // If url is null then redirect to research page if (url == null) { - url = `/${AppRoutes.research.uri}`; + url = `/${AppRoutes.datasets.uri}`; } this._router.navigateByUrl(url); diff --git a/src/app/dataset-detail/components/dataset-reuses/dataset-reuses.component.html b/src/app/dataset-detail/components/dataset-reuses/dataset-reuses.component.html index 520deeaa7566f807a099eaa76b721b12459f077a..ffc93f7b2612bc7631e4bdacc3f387118cf72b2c 100644 --- a/src/app/dataset-detail/components/dataset-reuses/dataset-reuses.component.html +++ b/src/app/dataset-detail/components/dataset-reuses/dataset-reuses.component.html @@ -36,7 +36,7 @@ <div class="posts-container" *ngIf="hasRelatedPosts"> <div class="post-item" *ngFor="let post of relatedNews"> - <a [routerLink]="['/', AppRoutes.articles.uri, post.slug]" class="link-without-decoration"> + <a [routerLink]="['/', AppRoutes.news.uri, post.slug]" class="link-without-decoration"> <div class="post-image" [ngStyle]="{'background-image': 'url(' + post.content.featureImage + ') '}"> </div> <div class="post-description"> diff --git a/src/app/dataset-detail/dataset-detail-routing.module.ts b/src/app/dataset-detail/dataset-detail-routing.module.ts index d9db43de1586b463cb7b3a5e293f1b3cd570e4d9..5144f73961d2e807b3268b7dde071bb43ffa4b37 100644 --- a/src/app/dataset-detail/dataset-detail-routing.module.ts +++ b/src/app/dataset-detail/dataset-detail-routing.module.ts @@ -17,44 +17,26 @@ export const routes: Routes = [ { path: AppRoutes.info.uri, component: DatasetInfoComponent, - data: { - title: AppRoutes.info.title, - }, }, { path: AppRoutes.data.uri, component: DatasetTableMapComponent, - data: { - title: AppRoutes.data.title, - }, }, { path: AppRoutes.resources.uri, component: DatasetAPIComponent, - data: { - title: AppRoutes.resources.title, - }, }, { path: AppRoutes.downloads.uri, component: DatasetDownloadsComponent, - data: { - title: AppRoutes.downloads.title, - }, }, { path: AppRoutes.otherResources.uri, component: DatasetDownloadsComponent, - data: { - title: AppRoutes.otherResources.title, - }, }, { path: AppRoutes.dataReuses.uri, component: DatasetReusesComponent, - data: { - title: AppRoutes.dataReuses.title, - }, }, ], }, diff --git a/src/app/datasets/components/filter-list/filter-list.component.ts b/src/app/datasets/components/filter-list/filter-list.component.ts index 518d95228e011b5c41bebf7e561cd7777031cbbf..99b500dc6fbb0a8b913ab3aa0a10b0a248baa9cb 100644 --- a/src/app/datasets/components/filter-list/filter-list.component.ts +++ b/src/app/datasets/components/filter-list/filter-list.component.ts @@ -105,7 +105,7 @@ export class FilterListComponent implements OnInit, OnDestroy { resetActiveAggregations() { this._datasetResearchService.resetActiveAggregations(); this._datasetResearchService.triggerSearchChange(); - this._location.go(AppRoutes.research.uri, ''); + this._location.go(AppRoutes.datasets.uri, ''); this._navigationHistoryService.add(this._location.path()); } diff --git a/src/app/datasets/components/results/result-dataset/result-dataset.component.ts b/src/app/datasets/components/results/result-dataset/result-dataset.component.ts index 5fa41dd5eb77e7f400ea72d4553320a4dcea2c5e..0c1745273db5a66b53324f6aaeded76226c8f7dd 100644 --- a/src/app/datasets/components/results/result-dataset/result-dataset.component.ts +++ b/src/app/datasets/components/results/result-dataset/result-dataset.component.ts @@ -47,7 +47,7 @@ export class ResultDatasetComponent implements OnInit { } get datasetDetailsURI() { - return this.dataset.hasMap || this.dataset.hasTable ? AppRoutes.data.uri : AppRoutes.info.uri; + return AppRoutes.info.uri; } } diff --git a/src/app/datasets/components/results/result-post/result-post.component.html b/src/app/datasets/components/results/result-post/result-post.component.html index c66145f64efae74db2db49bb67ae3ecdaaa7e403..8cb2c8f3e291da3792974ea09af6cc0ee1ab376c 100644 --- a/src/app/datasets/components/results/result-post/result-post.component.html +++ b/src/app/datasets/components/results/result-post/result-post.component.html @@ -11,7 +11,7 @@ {{post.content.category ? ' ' + notificationMessages.edito.news + ' : ' + post.content.category.name : ''}} </p> - <a [routerLink]="['/', AppRoutes.articles.uri, post.slug]" class="link-without-decoration"> + <a [routerLink]="['/', AppRoutes.news.uri, post.slug]" class="link-without-decoration"> <span class="post-description-title" [innerHTML]="!post.content.titleHighlight ? post.content.title : post.content.titleHighlight"> </span> @@ -25,4 +25,4 @@ </div> </div> -</ng-container> \ No newline at end of file +</ng-container> diff --git a/src/app/datasets/components/results/results-tab-scope/results-tab-scope.component.html b/src/app/datasets/components/results/results-tab-scope/results-tab-scope.component.html index 949eb1ac7dc753361b0696cc878c2caa402fc44a..fd67cc28682fe67a129a008b3263b86a3d8c2ac2 100644 --- a/src/app/datasets/components/results/results-tab-scope/results-tab-scope.component.html +++ b/src/app/datasets/components/results/results-tab-scope/results-tab-scope.component.html @@ -15,9 +15,4 @@ <span class="tab-label">{{ scopesResearch.services.label }}</span> <span class="tab-count">{{ countResults[scopesResearch.services.key] || 0 }}</span> </button> - <button (click)="changeScope(scopesResearch.post)" [ngClass]="{'is-selected': selectedScope.key === scopesResearch.post.key}" - [attr.aria-current]="selectedScope.key === scopesResearch.post.key ? 'page' : undefined"> - <span class="tab-label">{{ scopesResearch.post.label }}</span> - <span class="tab-count">{{ countResults[scopesResearch.post.key] || 0 }}</span> - </button> </div> diff --git a/src/app/datasets/components/results/results.component.html b/src/app/datasets/components/results/results.component.html index 00db0587ce523103452448568108a0ff10adf22b..2e2ae4a1b3fa0c9903662cb1dab8e3bd0aacd1ef 100644 --- a/src/app/datasets/components/results/results.component.html +++ b/src/app/datasets/components/results/results.component.html @@ -1,3 +1,7 @@ +<div class="page-header-container"> + <app-page-header [pageInfo]="pageHeaderInfo"></app-page-header> + <p *ngIf="intro">{{ intro }}</p> +</div> <div class="main-content"> <div class="filter-button-touch column is-hidden-desktop" (click)="toggleFilters()"> diff --git a/src/app/datasets/components/results/results.component.scss b/src/app/datasets/components/results/results.component.scss index 6ce763b8a5b851bc7f505b7cabf098eed23a1dae..de5c06a0076f8b120a4d212a20fd757e2c743820 100644 --- a/src/app/datasets/components/results/results.component.scss +++ b/src/app/datasets/components/results/results.component.scss @@ -14,6 +14,20 @@ $sticky-distance: $header-bar-height + 32px; } } + +.page-header-container { + background-color: white; + padding: 0 1.25rem 0 1.25rem; + margin:2rem; + margin-bottom: 0rem; + border-radius: 8px; + box-shadow: 0px 6px 12px rgb(129 128 128 / 10%); + + p { + padding-bottom:2em; + } +} + @media (max-width: $tablet) { .header-dataset { flex-direction: column-reverse; diff --git a/src/app/datasets/components/results/results.component.ts b/src/app/datasets/components/results/results.component.ts index 983486d0e59c5731cb140b946d65352e2686bbba..119f4e1fa75e8e964effa090761f43944767fae9 100644 --- a/src/app/datasets/components/results/results.component.ts +++ b/src/app/datasets/components/results/results.component.ts @@ -3,13 +3,13 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Meta } from '@angular/platform-browser'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; -import { metaDescription, notificationMessages } from '../../../../i18n/traductions'; +import { metaDescription, introText, notificationMessages, pageTitles } from '../../../../i18n/traductions'; import { Notification } from '../../../core/models'; import { NotificationService } from '../../../core/services'; import { CMSContent } from '../../../editorialisation/models'; import { IScope } from '../../../elasticsearch/models'; import { AppRoutes } from '../../../routes'; -import { Dataset, IMetadataLink, PaginatorOptions } from '../../../shared/models'; +import { Dataset, IMetadataLink, IPageHeaderInfo, PaginatorOptions } from '../../../shared/models'; import { SearchSuggestion } from '../../models'; import { DatasetResearchService, ResearchUrlService } from '../../services'; @@ -24,6 +24,11 @@ export class ResultsComponent implements OnInit, OnDestroy { results: Dataset[] | CMSContent[]; + pageHeaderInfo: IPageHeaderInfo = { + title: pageTitles.datasets + }; + intro: string = introText.research; + countResults: []; hasParams: boolean = false; searchChangeSub: Subscription; @@ -47,6 +52,8 @@ export class ResultsComponent implements OnInit, OnDestroy { ngOnInit() { + console.log(`Titre vaut : ${ pageTitles.datasets }.`); + console.log(pageTitles); // Set the title and description for the research page this._meta.updateTag({ name: 'description', content: metaDescription.research }); diff --git a/src/app/datasets/datasets-routing.module.ts b/src/app/datasets/datasets-routing.module.ts index c296462c479cb1ee22623a3c391e7517b9eea168..849eb19788d5edda4660e39bfe07d42d1440036e 100644 --- a/src/app/datasets/datasets-routing.module.ts +++ b/src/app/datasets/datasets-routing.module.ts @@ -5,10 +5,10 @@ import { ResultsComponent } from './components'; export const routes: Routes = [ { - path: AppRoutes.research.uri, + path: AppRoutes.datasets.uri, component: ResultsComponent, data: { - title: AppRoutes.research.title, + title: AppRoutes.datasets.title, }, }, { diff --git a/src/app/datasets/services/dataset-research.service.ts b/src/app/datasets/services/dataset-research.service.ts index 02d037e58bee55dfa9c873d467fd5204e7859651..1308666b27a2327b2a499f75f57cc21901118296 100644 --- a/src/app/datasets/services/dataset-research.service.ts +++ b/src/app/datasets/services/dataset-research.service.ts @@ -53,7 +53,6 @@ export class DatasetResearchService { if (this._elasticsearchOptions.shouldAggregateResultCount) { this._resultsCount = []; const countScopes = e.aggregations['count_by_scope'].buckets; - let countDatasets = 0; countScopes.forEach((bucket) => { if (scopesResearch.datasets.elasticType.includes(bucket.key)) { @@ -74,7 +73,7 @@ export class DatasetResearchService { // All scope const countAll = this._resultsCount.reduce((acc, obj) => { - const count = obj.scopeKey !== scopesResearch.page.key ? acc + obj.count : 0; + const count = obj.scopeKey !== (scopesResearch.page.key&&scopesResearch.post.key) ? acc + obj.count : 0; return count; // tslint:disable-next-line:align }, 0); @@ -480,11 +479,11 @@ export class DatasetResearchService { this._elasticsearchOptions.shouldAggregateResultCount = true; this._elasticsearchOptions.sortOptions.value = (value && true) ? 'relevance' : 'date'; this._elasticsearchOptions.sortOptions.order = 'desc'; - if (this._router.url.split('/').pop() !== AppRoutes.research.uri) { + if (this._router.url.split('/').pop() !== AppRoutes.datasets.uri) { if (value === '') { - this._router.navigate(['/', `${AppRoutes.research.uri}`]); + this._router.navigate(['/', `${AppRoutes.datasets.uri}`]); } else { - this._router.navigate(['/', `${AppRoutes.research.uri}`], { queryParams: { q: value } }); + this._router.navigate(['/', `${AppRoutes.datasets.uri}`], { queryParams: { q: value } }); } } @@ -504,6 +503,7 @@ export class DatasetResearchService { this._lastFilterClicked = null; this._elasticsearchOptions.searchString = ''; this._elasticsearchOptions.pageIndex = 0; + this._elasticsearchOptions.pageSize = 5; this._elasticsearchOptions.scope = scopesResearch.all; this.resetActiveAggregations(); if (triggerNext) { @@ -592,6 +592,10 @@ export class DatasetResearchService { return this._elasticsearchOptions.scope; } + set pageSize(value: number) { + this._elasticsearchOptions.pageSize = value; + } + /* Result number */ get resultsCount(): ICountScope[] { diff --git a/src/app/datasets/services/research-url.service.ts b/src/app/datasets/services/research-url.service.ts index d698bee10497fda5bdd67e5de04f5b2f6bf7dd78..a63386298782545688b36207d86ded445cca96ac 100644 --- a/src/app/datasets/services/research-url.service.ts +++ b/src/app/datasets/services/research-url.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { NavigationHistoryService } from '../../core/services'; import { Aggregation, IElasticsearchOptions, ISortOption } from '../../elasticsearch/models'; import { AppRoutes } from '../../routes'; +import { Router } from '@angular/router'; import { scopesResearch } from '../../shared/variables'; @Injectable() @@ -13,7 +14,8 @@ export class ResearchUrlService { constructor( private _location: Location, - private _navigationHistoryService: NavigationHistoryService + private _navigationHistoryService: NavigationHistoryService, + private _router: Router, ) { } // Get the ES options from parameters @@ -79,7 +81,7 @@ export class ResearchUrlService { setParameter(key: string, searchValue: string) { this._parameters[key] = searchValue; const params = this.generateUrlParams(); - this._location.go(AppRoutes.research.uri, params); + this._location.go(AppRoutes.datasets.uri, params); this._navigationHistoryService.add(this._location.path()); } @@ -134,7 +136,7 @@ export class ResearchUrlService { } } const params = this.generateUrlParams(); - this._location.go(AppRoutes.research.uri, params); + this._location.go(AppRoutes.datasets.uri, params); this._navigationHistoryService.add(this._location.path()); } @@ -163,7 +165,7 @@ export class ResearchUrlService { setPaginationParameter(pageIndex: number) { this._parameters['page'] = pageIndex + 1; const params = this.generateUrlParams(); - this._location.go(AppRoutes.research.uri, params); + this._location.go(this._router.url, params); } setSortParameter(option: ISortOption) { @@ -171,7 +173,7 @@ export class ResearchUrlService { const value = option.order === 'desc' ? `-${option.value}` : option.value; this._parameters['sort'] = value; const params = this.generateUrlParams(); - this._location.go(AppRoutes.research.uri, params); + this._location.go(AppRoutes.datasets.uri, params); this._navigationHistoryService.add(this._location.path()); } diff --git a/src/app/editorialisation/components/cms-posts-list/cms-drafts-list.component.html b/src/app/editorialisation/components/cms-drafts-list/cms-drafts-list.component.html similarity index 85% rename from src/app/editorialisation/components/cms-posts-list/cms-drafts-list.component.html rename to src/app/editorialisation/components/cms-drafts-list/cms-drafts-list.component.html index b4d3fffcb36ea298f3f7d214894ae937f4154dee..4c76b24c73cbb1f4775f487e6e27d62714586025 100644 --- a/src/app/editorialisation/components/cms-posts-list/cms-drafts-list.component.html +++ b/src/app/editorialisation/components/cms-drafts-list/cms-drafts-list.component.html @@ -3,7 +3,7 @@ <div class="columns is-multiline"> <div class="column is-3 item is-12-touch" *ngFor="let draft of drafts"> - <a [routerLink]="['/', AppRoutes.articles.uri, draft.slug]" class="link-without-decoration"> + <a [routerLink]="['/', AppRoutes.news.uri, draft.slug]" class="link-without-decoration"> <div> <img src="{{draft.content.featureImage}}" alt="Image principale du brouillon"> </div> @@ -19,4 +19,4 @@ <ng-template #postsErrorTemplate> <div class="error-template">Couldn't load list of posts</div> -</ng-template> \ No newline at end of file +</ng-template> diff --git a/src/app/editorialisation/components/cms-posts-list/cms-drafts-list.component.scss b/src/app/editorialisation/components/cms-drafts-list/cms-drafts-list.component.scss similarity index 100% rename from src/app/editorialisation/components/cms-posts-list/cms-drafts-list.component.scss rename to src/app/editorialisation/components/cms-drafts-list/cms-drafts-list.component.scss diff --git a/src/app/editorialisation/components/cms-posts-list/cms-drafts-list.component.ts b/src/app/editorialisation/components/cms-drafts-list/cms-drafts-list.component.ts similarity index 100% rename from src/app/editorialisation/components/cms-posts-list/cms-drafts-list.component.ts rename to src/app/editorialisation/components/cms-drafts-list/cms-drafts-list.component.ts diff --git a/src/app/editorialisation/components/cms-page/cms-page.component.ts b/src/app/editorialisation/components/cms-page/cms-page.component.ts index 75aadb548578aadcbe88af5962ed6acb2f9bb519..6a7f533c037cd072a6e1ac953ce2de2683776bfa 100644 --- a/src/app/editorialisation/components/cms-page/cms-page.component.ts +++ b/src/app/editorialisation/components/cms-page/cms-page.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core'; -import { DomSanitizer, Meta, SafeHtml } from '@angular/platform-browser'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { environment } from '../../../../environments/environment'; import { ToolsService } from '../../../core/services/tools.service'; import { AppRoutes } from '../../../routes'; import { IPageHeaderInfo } from '../../../shared/models'; import { CMSContent } from '../../models'; -import { EditorialisationService } from '../../services'; +import { EditorialisationService, SeoSErvice } from '../../services'; @Component({ selector: 'app-cms-page', @@ -26,7 +26,7 @@ export class CMSPageComponent implements OnInit { private sanitizer: DomSanitizer, private _toolsService: ToolsService, private _router: Router, - private _meta: Meta, + private _seoService: SeoSErvice, ) { } @@ -42,14 +42,14 @@ export class CMSPageComponent implements OnInit { this._editorialisationService.getPage(page).subscribe((page) => { this.page = page; - // Set the title and description for a CMS page - this._meta.updateTag({ name: 'description', content: this.page.content.excerpt }); if (!(this.page instanceof CMSContent)) { this._router.navigate(['/', AppRoutes.page404.uri]); } else { this.safePageContent = this.sanitizer.bypassSecurityTrustHtml(this._toolsService.decorateRichText(this.page.content.html)); this.pageHeaderInfo.title = this.page.content.title; + + this._seoService.setPostSEO(this.page); } }); }); diff --git a/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts b/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts index 64d1df7a60f614dd01a27107a0669fdc4bd40b50..310ac417c79eca8f113de644b1a24b796b9bea81 100644 --- a/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts +++ b/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts @@ -1,13 +1,15 @@ import { DatePipe } from '@angular/common'; import { Component, OnInit } from '@angular/core'; -import { DomSanitizer, Meta, SafeHtml } from '@angular/platform-browser'; +import { DomSanitizer, Meta, SafeHtml, Title } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; -import { datasetStatistics, notificationMessages } from '../../../../i18n/traductions'; +import { notificationMessages } from '../../../../i18n/traductions'; import { ToolsService } from '../../../core/services/tools.service'; import { ElasticsearchService } from '../../../elasticsearch/services/elasticsearch.service'; +import { SeoSErvice } from '../../services/seo.service' import { AppRoutes } from '../../../routes'; import { IPageHeaderInfo, Metadata, typesMetadata } from '../../../shared/models'; import { CMSContent } from '../../models/cms-content.model'; +import { environment } from '../../../../environments/environment'; @Component({ selector: 'app-cms-post-detail', @@ -23,7 +25,7 @@ export class CMSPostDetailComponent implements OnInit { title: '', shareButtons: { isActive: true, - matchingUriInSeoService: 'articles', + matchingUriInSeoService: 'news', }, }; relations: { @@ -36,7 +38,9 @@ export class CMSPostDetailComponent implements OnInit { private _datePipe: DatePipe, private _sanitizer: DomSanitizer, private _elasticSearchService: ElasticsearchService, + private _seoService: SeoSErvice, private _toolsService: ToolsService, + private _titleService: Title, private _meta: Meta, ) { } @@ -47,7 +51,7 @@ export class CMSPostDetailComponent implements OnInit { if (this.post) { // Set the title and description for a CMS post - this._meta.updateTag({ name: 'description', content: this.post.content.excerpt }); + this._seoService.setPostSEO(this.post); this.safePostContent = this._sanitizer.bypassSecurityTrustHtml(this._toolsService.decorateRichText(this.post.content.html)); @@ -80,7 +84,7 @@ export class CMSPostDetailComponent implements OnInit { } } - + setBackupImage(metadata: Metadata) { // Init the image property to make sure that 'url' is accessible in the following lines diff --git a/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.html b/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.html new file mode 100644 index 0000000000000000000000000000000000000000..3237d0f2d0c963196791a8f173f215b0aeba571d --- /dev/null +++ b/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.html @@ -0,0 +1,37 @@ +<section > + <div class="page-container is-fullwidth"> + <div class="page-header-container"> + <app-page-header [pageInfo]="pageHeaderInfo"></app-page-header> + <p *ngIf="intro">{{ intro }}</p> + </div> + <div class="posts"> + <div class="post-container"> + <div class="is-4-desktop is-8-tablet" *ngFor="let post of posts"> + <div class="post-item"> + <a [routerLink]="['/', AppRoutes.news.uri, post.slug]" class="link-without-decoration"> + <div class="post-image" [ngStyle]="{'background-image': 'url(' + post.content.featureImage + ') '}"> + </div> + <div class="post-description"> + <p class="post-description-date"> + {{ post.content.publicationDate | date: 'dd.MM.yyyy' }} + {{post.content.category ? ' - ' + post.content.category.name : ''}} + </p> + <p class="post-description-title" [innerHTML]=post.content.title></p> + </div> + </a> + </div> + </div> + <div class="pagination-bottom"> + <app-paginator *ngIf="paginator.length > 0" [length]="paginator.length" [pageSize]="paginator.pageSize" + [pageSizeOptions]="paginator.pageSizeOptions" [pageIndex]="paginator.pageIndex" [loading]="isLoading" + [showFirstLastButtons]="true" (page)="changePagination($event)" (pageSizeChanged)="changePageSize($event)"> + </app-paginator> + </div> + </div> + </div> + </div> +</section> + +<ng-template #postsErrorTemplate> + <div class="error-template">Couldn't load list of posts</div> +</ng-template> diff --git a/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.scss b/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..19b7642f726fb578464f16c8ed8a43be226c97a7 --- /dev/null +++ b/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.scss @@ -0,0 +1,211 @@ +@import '../../../../scss/variables.scss'; +@import '../../../../../node_modules/bulma/sass/utilities/all'; + + +.section { + text-align: center; + padding-bottom: 3rem; +} +.page-header-container { + background-color: white; + padding: 0 1.25rem 0 1.25rem; + + p { + padding-bottom:2em; + } +} + +.posts { + flex-grow: 1; + padding-top:1rem; + background: linear-gradient(to bottom, $grey-background-color, #dedede); + display: flex; + + justify-content: center; + + .post-container { + width: 100%; + margin-bottom: 1rem; + // Make the icon go behind in some screen width when menu is pushed. + z-index: 3; + + @media screen and (min-width: $tablet) { + width: 30.5rem; + } + + @media screen and (min-width: $desktop) { + width: unset; + display: grid; + grid-template-rows: auto; + grid-column-gap: 1.5rem; + grid-template-columns: repeat(3, 17.5rem); + } + + @media screen and (min-width: $fullhd) { + grid-template-columns: repeat(3, 22.5rem); + } + } + + .posts-header { + grid-row: 1; + grid-column: 1 / span 3; + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; + + @media screen and (min-width: $desktop) { + margin-bottom: 0; + } + } + + .posts-title { + @media screen and (min-width: $desktop) { + text-align: left; + } + + span { + font-size: 1.5rem; + line-height: 1.4; + font-weight: 600; + } + } + + .posts-all-news { + @media screen and (min-width: $desktop) { + text-align: right; + } + + button { + height: 2.75rem; + width: 7.625rem; + vertical-align: middle; + } + + span { + font-size: 0.625rem; + line-height: 1; + } + } + + .post-item { + margin: auto; + margin-bottom: 2rem; + + @media screen and (min-width: $desktop) { + width: unset; + max-height: 15rem; + grid-row: 2; + } + + color: $brand-color; + + a { + display: flex; + flex-direction: column; + height: 100%; + + &:hover { + text-decoration: none; + } + + @media screen and (max-width: $tablet) { + margin:0.5rem; + } + } + + .post-image { + min-height: 7.5rem; + width: 100%; + background-position: center; + background-size: cover; + background-repeat: no-repeat; + border-radius: 0.25rem 0.25rem 0 0; + filter: none; + transition: filter 0.5s ease-in-out; + } + + .post-description { + flex-grow: 1; + background-color: #ffff; + border-radius: 0 0 0.25rem 0.25rem; + padding: 1rem; + + @media screen and (min-width: $desktop) { + min-height: 7rem; + } + + .post-description-date { + margin-bottom: 0.5rem; + font-size: 0.75rem; + text-transform: uppercase; + color: $grey-dark-color; + line-height: 1; + } + + .post-description-title { + font-size: 1.125rem; + font-weight: bold; + } + } + + a:hover .post-description-title { + text-decoration: underline; + } + + &:hover { + .post-image { + filter: grayscale(100%); + } + } + } +} + +.pagination-bottom { + clear:both; + display: flex; + grid-column: 1/span 3; + justify-content: center; +} + + + +/* .posts { + background-color: $grey-background-color; + + .item { + padding: 1rem 1rem; + color: $brand-color; + + img { + max-height: 10rem; + filter: grayscale(100%); + transition: filter 0.5s ease-in-out; + } + + a { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + } + + a:hover { + text-decoration: none; + color: $brand-color; + } + + &:hover { + background-color: rgb(236, 244, 247); + + h3 { + color: $tomato-color; + } + + img { + filter: grayscale(0); + } + } + } +} + */ diff --git a/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.ts b/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..51ce8728296d12fb98096d0ed24b7ade2a79973d --- /dev/null +++ b/src/app/editorialisation/components/cms-posts-list/cms-posts-list.component.ts @@ -0,0 +1,91 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { AppRoutes } from '../../../routes'; +import { CMSContent } from '../../models/cms-content.model'; +import { IPageHeaderInfo } from '../../../shared/models'; +import { pageTitles, introText, metaDescription } from '../../../../i18n/traductions'; +import { PaginatorOptions } from '../../../shared/models'; +import { ElasticsearchService } from '../../../elasticsearch/services/elasticsearch.service'; +import { DatasetResearchService } from '../../../datasets/services'; +import { scopesResearch } from '../../../shared/variables'; +import { Meta } from '@angular/platform-browser'; + +@Component({ + selector: 'app-cms-posts-list', + templateUrl: './cms-posts-list.component.html', + styleUrls: ['./cms-posts-list.component.scss'], +}) +export class CMSPostsListComponent implements OnInit, OnDestroy { + + posts: CMSContent[]; + paginator: PaginatorOptions; + countResults = []; + pageHeaderInfo: IPageHeaderInfo = { + title: pageTitles.news, + }; + intro: string = introText.news; + + private _pageIndex: number = 1; + private _pageSize: number = 9; + + + latestPosts: any; + AppRoutes = AppRoutes; + + constructor( + private _elasticsearchService: ElasticsearchService, + private _datasetResearchService: DatasetResearchService, + private _meta: Meta, + ) { } + + ngOnInit() { + + this._meta.updateTag({ name: 'description', content: metaDescription.news }); + this._datasetResearchService.resetResearch(); + this._datasetResearchService.scopeReasearch = scopesResearch.post; + const countResults = []; + this._datasetResearchService.pageSize = 9; + + this.paginator = { + pageIndex: this._datasetResearchService.pageIndex + 1, + length: 0, + pageSize: this._datasetResearchService.pageSize, + pageSizeOptions: [5, 10, 20], + }; + + this.search(); + } + + // When pagination is changed by user, we update results with new pagination options + changePagination(pageIndex) { + this._datasetResearchService.shouldAggregateResultCount = false; + this._datasetResearchService.shouldAggregateFilters = false; + this._datasetResearchService.paginationChanged(this.paginator.pageSize, pageIndex - 1); + + this.search(); + } + + private search() { + this._datasetResearchService.getResults().subscribe((posts) => { + this.posts = []; + posts.forEach((result) => { + this.posts.push(result); + }); + //const position = this._viewportScroller.getScrollPosition(); + this.countResults = []; + this._datasetResearchService.resultsCount.forEach((item) => { + this.countResults[item.scopeKey] = item.count || 0; + }); + + this.paginator.pageSize = this._datasetResearchService.pageSize; + this.paginator.pageIndex = this._datasetResearchService.pageIndex + 1; + + // Set pagination depending on the selected scope + this.paginator.length = this.countResults[scopesResearch.post.key]; + //this._viewportScroller.scrollToPosition(position); + }); + } + + ngOnDestroy() { + this._datasetResearchService.resetResearch(); + } +} diff --git a/src/app/editorialisation/components/contribution/contribution.component.ts b/src/app/editorialisation/components/contribution/contribution.component.ts index 99ec5897a524bc0a2ca64ade2f1fc71978115dcb..9c27092c48c1bab888f7f48f691ecbd944f1d6c1 100644 --- a/src/app/editorialisation/components/contribution/contribution.component.ts +++ b/src/app/editorialisation/components/contribution/contribution.component.ts @@ -3,6 +3,7 @@ import { IPageHeaderInfo } from '../../../shared/models'; import { ActivatedRoute } from '@angular/router'; import { pageTitles, contactTrad } from '../../../../i18n/traductions'; import { AppRoutes } from '../../../routes'; +import { SeoSErvice } from '../../services'; @Component({ selector: 'app-contribution', @@ -19,6 +20,7 @@ export class ContributionComponent implements OnInit { constructor( private _route: ActivatedRoute, + private _seoService: SeoSErvice, ) { } diff --git a/src/app/editorialisation/components/home/home.component.html b/src/app/editorialisation/components/home/home.component.html index e8003845edfee234baef3a243e69089e15682a6f..db854474578f13e1aef20f3696db40d7d0866e4f 100644 --- a/src/app/editorialisation/components/home/home.component.html +++ b/src/app/editorialisation/components/home/home.component.html @@ -17,7 +17,7 @@ </div> <div class="search column is-7-desktop is-8-tablet "> <app-search-bar class="app-search-bar"></app-search-bar> - <a class="explore-link" [routerLink]="['/', AppRoutes.research.uri]" (click)="trackExploreButtonEvent()"> + <a class="explore-link" [routerLink]="['/', AppRoutes.datasets.uri]" (click)="trackExploreButtonEvent()"> <button class="button explore-button" i18n="@@home.explore">Explore</button> </a> </div> @@ -46,7 +46,7 @@ <span i18n="@@home.news">News</span> </div> <div class="posts-all-news"> - <button class="button" (click)="goToPostsResearch()" i18n="@@home.allnews"> + <button class="button" [routerLink]="['/', AppRoutes.news.uri]" i18n="@@home.allnews"> All news </button> </div> @@ -54,7 +54,7 @@ <div class="post-item is-4-desktop is-8-tablet" *ngFor="let post of latestPosts"> - <a [routerLink]="['/', AppRoutes.articles.uri, post.slug]" class="link-without-decoration"> + <a [routerLink]="['/', AppRoutes.news.uri, post.slug]" class="link-without-decoration"> <div class="post-image" [ngStyle]="{'background-image': 'url(' + post.content.featureImage + ') '}"> </div> <div class="post-description"> diff --git a/src/app/editorialisation/components/home/home.component.ts b/src/app/editorialisation/components/home/home.component.ts index 9d9fab409626759df4d8203276088f82baf10860..49baebf709786c1c7d191003b77be3fb65f17327 100644 --- a/src/app/editorialisation/components/home/home.component.ts +++ b/src/app/editorialisation/components/home/home.component.ts @@ -42,9 +42,6 @@ export class HomeComponent implements OnInit { ) { } ngOnInit() { - // Set the title and description for the home page - this._meta.updateTag({ name: 'description', content: metaDescription.home }); - this._datasetResearchService.resetResearch(false); this.latestPosts = []; @@ -105,7 +102,7 @@ export class HomeComponent implements OnInit { goToPostsResearch() { this._datasetResearchService.resetResearch(); this._datasetResearchService.scopeReasearch = scopesResearch.post; - this._router.navigate(['/', AppRoutes.research.uri]); + this._router.navigate(['/', AppRoutes.datasets.uri]); } trackExploreButtonEvent() { diff --git a/src/app/editorialisation/components/index.ts b/src/app/editorialisation/components/index.ts index 609725ab34fd1bb5552bce90cd24437582e5cd64..33831dca3c5aac2aee58c53020c0a06ea60a6c27 100644 --- a/src/app/editorialisation/components/index.ts +++ b/src/app/editorialisation/components/index.ts @@ -1,5 +1,6 @@ import { CMSPageComponent } from './cms-page/cms-page.component'; -import { CMSDraftsListComponent } from './cms-posts-list/cms-drafts-list.component'; +import { CMSDraftsListComponent } from './cms-drafts-list/cms-drafts-list.component'; +import { CMSPostsListComponent } from './cms-posts-list/cms-posts-list.component'; import { HomeComponent } from './home/home.component'; // tslint:disable-next-line:max-line-length import { CMSPostDetailComponent } from './cms-post-detail/cms-post-detail.component'; @@ -15,6 +16,7 @@ import { ReuseDetailComponent } from './reuse-detail/reuse-detail.component'; export { CMSPageComponent, CMSDraftsListComponent, + CMSPostsListComponent, CMSPostDetailComponent, HomeComponent, OrganizationsComponent, @@ -30,6 +32,7 @@ export { export const EditorialisationComponents = [ CMSPageComponent, CMSDraftsListComponent, + CMSPostsListComponent, CMSPostDetailComponent, HomeComponent, OrganizationsComponent, diff --git a/src/app/editorialisation/components/reuse-detail/reuse-detail.component.ts b/src/app/editorialisation/components/reuse-detail/reuse-detail.component.ts index 880a48e6fd25a51f8f427586ac978a6da8ccabab..294601f8c3af8eccdf5d9def735887e73d8587b1 100644 --- a/src/app/editorialisation/components/reuse-detail/reuse-detail.component.ts +++ b/src/app/editorialisation/components/reuse-detail/reuse-detail.component.ts @@ -6,7 +6,7 @@ import { ElasticsearchService } from '../../../elasticsearch/services/elasticsea import { AppRoutes } from '../../../routes'; import { IPageHeaderInfo, Metadata, typesMetadata } from '../../../shared/models'; import { Reuse } from '../../models'; -import { ReusesService } from '../../services'; +import { ReusesService, SeoSErvice } from '../../services'; @Component({ selector: 'app-reuse-detail', @@ -26,6 +26,7 @@ export class ReuseDetailComponent implements OnInit { private _reusesService: ReusesService, private _route: ActivatedRoute, private _elasticSearchService: ElasticsearchService, + private _seoSErvice: SeoSErvice, ) { } ngOnInit() { @@ -40,6 +41,8 @@ export class ReuseDetailComponent implements OnInit { return this._elasticSearchService.getDatasetMetadata(slug); }); + this._seoSErvice.setReuseSEO(this.reuse); + forkJoin(calls).pipe( map((response) => { return response.map((e, i) => { diff --git a/src/app/editorialisation/components/site-map/site-map.component.html b/src/app/editorialisation/components/site-map/site-map.component.html index a725a92df6344d513c2f9c2b967e951daa6f9e30..11518df0b630220d10bd2671465dc165169743eb 100644 --- a/src/app/editorialisation/components/site-map/site-map.component.html +++ b/src/app/editorialisation/components/site-map/site-map.component.html @@ -6,7 +6,8 @@ <p class="pages-group-title" i18n="@@sitemap.mainPages">Main pages</p> <ul class="pages-list"> <li><a class="link-1" [routerLink]="['/', AppRoutes.home.uri]" i18n="@@sitemap.home">Home</a></li> - <li><a class="link-1" [routerLink]="['/', AppRoutes.research.uri]" i18n="@@sitemap.research">Research</a></li> + <li><a class="link-1" [routerLink]="['/', AppRoutes.datasets.uri]" i18n="@@sitemap.datasets">Datasets</a></li> + <li><a class="link-1" [routerLink]="['/', AppRoutes.news.uri]" i18n="@@sitemap.news">News</a></li> <li><a class="link-1" [routerLink]="['/', AppRoutes.partners.uri]" i18n="@@sitemap.partners">Partners</a></li> <li><a class="link-1" [routerLink]="['/', AppRoutes.approach.uri]" i18n="@@sitemap.approach">Approach</a></li> <li><a class="link-1" [routerLink]="['/', AppRoutes.documentation.uri]" i18n="@@sitemap.documentation">Documentation</a></li> @@ -17,11 +18,11 @@ <div class="column"> <p class="pages-group-title" i18n="@@sitemap.secondaryPages">Secondary pages</p> <ul class="pages-list"> - <li><a class="link-1" [routerLink]="['/', AppRoutes.accessibility.uri]" - i18n="@@sitemap.accessibility">Accessibility</a></li> - <li><a class="link-1" [routerLink]="['/', AppRoutes.legalNotices.uri]" i18n="@@sitemap.legalNotices">Legal - notices</a></li> <li><a class="link-1" [routerLink]="['/', AppRoutes.contact.uri]" i18n="@@sitemap.contact">Contact us</a></li> + <li><a class="link-1" [routerLink]="['/', AppRoutes.changelog.uri]" i18n="@@sitemap.changelog">Last changes</a></li> + <li><a class="link-1" [routerLink]="['/', AppRoutes.accessibility.uri]" i18n="@@sitemap.accessibility">Accessibility</a></li> + <li><a class="link-1" [routerLink]="['/', AppRoutes.siteMap.uri]" i18n="@@footer.sitemap">Sitemap</a></li> + <li><a class="link-1" [routerLink]="['/', AppRoutes.legalNotices.uri]" i18n="@@sitemap.legalNotices">Legal notices</a></li> <li><a class="link-1" [routerLink]="['/', AppRoutes.credits.uri]" i18n="@@sitemap.credits">Credits</a></li> <li><a class="link-1" [routerLink]="['/', AppRoutes.cgu.uri]" i18n="@@sitemap.cgu">Terms of use</a> </li> diff --git a/src/app/editorialisation/editorialisation-routing.module.ts b/src/app/editorialisation/editorialisation-routing.module.ts index ca9ea8c26ef583d33efdfd4aeda2bb00e1540323..8327b1590464c951560b19c2d006107511a77e48 100644 --- a/src/app/editorialisation/editorialisation-routing.module.ts +++ b/src/app/editorialisation/editorialisation-routing.module.ts @@ -1,7 +1,9 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AppRoutes } from '../routes'; -import { ChangelogComponent, CMSDraftsListComponent, CMSPageComponent, ContributionComponent, HomeComponent, OrganizationsComponent, ReuseDetailComponent, ReusesListComponent, SiteMapComponent } from './components'; +import { ChangelogComponent, CMSDraftsListComponent, CMSPageComponent, CMSPostsListComponent, + ContributionComponent, HomeComponent, OrganizationsComponent, + ReuseDetailComponent, ReusesListComponent, SiteMapComponent } from './components'; import { CMSPostDetailComponent } from './components/cms-post-detail/cms-post-detail.component'; import { CreditsComponent } from './components/credits/credits.component'; import { CreditsActivatedGuard, EditorialisationGuards, PartnersActivatedGuard, ReusesActivatedGuard } from './guards'; @@ -116,13 +118,20 @@ export const routes: Routes = [ canActivate: [ReusesActivatedGuard], }, { - path: `${AppRoutes.articles.uri}/:id`, + path: AppRoutes.news.uri, + component: CMSPostsListComponent, + data: { + title: AppRoutes.news.title + }, + }, + { + path: `${AppRoutes.news.uri}/:id`, component: CMSPostDetailComponent, resolve: { post: PostDetailResolver, }, data: { - title: AppRoutes.articles.title, + title: AppRoutes.news.title, }, }, { diff --git a/src/app/editorialisation/models/cms-content.model.ts b/src/app/editorialisation/models/cms-content.model.ts index a3e135feecf7bb66d397051c3ba00c2acf962344..9d7a45d9b5874ee610471fdad552c6feb8f1ea7b 100644 --- a/src/app/editorialisation/models/cms-content.model.ts +++ b/src/app/editorialisation/models/cms-content.model.ts @@ -34,6 +34,11 @@ export interface IGhostContentResponse { featured: boolean; tags: IGhostTag[]; highlight?: IHighlight[]; + meta_description: string; + meta_title?: string; + og_title?: string; + og_description?: string; + og_image?: string; } export interface IHighlight { @@ -100,14 +105,28 @@ export class GhostContentResponse { modificationDate: number; highlight?: string[]; titleHighlight?: string; + meta_description?: string; + meta_title?: string; + og_title?: string; + og_description?: string; + og_image?: string; constructor(data: IGhostContentResponse) { this.id = data.id; this.status = (data.status != null) ? data.status : ''; this.title = (data.title != null) ? data.title : ''; this.html = (data.html != null) ? data.html : ''; + + this.meta_title = (data.meta_title != null) ? data.meta_title: this.title; + this.og_title=(data.og_title != null) ? data.og_title : this.title; + this.excerpt = (data.excerpt != null) ? data.excerpt : ''; + this.meta_description = data.meta_description ; + this.og_description=(data.og_description != null) ? data.og_description : this.meta_description; + this.featureImage = data.feature_image; + this.og_image = this.featureImage; + this.publicationDate = (data.published_at != null) ? Date.parse(data.published_at) : 0; this.modificationDate = (data.updated_at != null) ? Date.parse(data.updated_at) : 0; diff --git a/src/app/editorialisation/services/index.ts b/src/app/editorialisation/services/index.ts index 2577fdec76f895098e5e50cee52b32557930b256..d1461e62fcfce8d5a969aa6f0b92e7476a189227 100644 --- a/src/app/editorialisation/services/index.ts +++ b/src/app/editorialisation/services/index.ts @@ -3,6 +3,7 @@ import { OrganizationsService } from './organizations.service'; import { CreditsService } from './credits.service'; import { ChangelogsService } from './changelog.service'; import { ReusesService } from './reuses.service'; +import { SeoSErvice } from './seo.service'; export { EditorialisationService, @@ -10,6 +11,7 @@ export { CreditsService, ChangelogsService, ReusesService, + SeoSErvice, }; // tslint:disable-next-line:variable-name @@ -19,4 +21,5 @@ export const EditorialisationServices = [ CreditsService, ChangelogsService, ReusesService, + SeoSErvice, ]; diff --git a/src/app/editorialisation/services/seo.service.ts b/src/app/editorialisation/services/seo.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..b94e6e940ca399fe5c7c03969f77f2f2af83ca9f --- /dev/null +++ b/src/app/editorialisation/services/seo.service.ts @@ -0,0 +1,119 @@ +import { Injectable } from '@angular/core'; +import { Meta, Title } from '@angular/platform-browser'; +import { environment } from '../../../environments/environment'; +import { metaDescription, pageTitles } from '../../../i18n/traductions'; +import { AppRoutes } from '../../routes'; +import { Metadata } from '../../shared/models'; +import { CMSContent, Reuse } from '../models'; + + +@Injectable() +export class SeoSErvice { + + private _lang: string; + private _defaultImg: string; + private _defaultDesc: string; + private _defaultTitle: string; + + constructor( + private _titleService: Title, + private _metaService: Meta + ) { + this._lang = window.location.href.includes(environment.angularAppHost.en) ? 'en' : 'fr'; + + this._defaultImg = this._metaService.getTag("property='og:image'").content; + this._defaultDesc = metaDescription.home; + this._defaultTitle = this._titleService.getTitle(); + } + + setPostSEO(post:CMSContent) + { + const imageUrl = (post.content.og_image != null) ? + post.content.og_image : post.content.featureImage; + + var description: string = ''; + if (post.content.meta_description) { + description = post.content.meta_description; + } + else { + description = post.content.excerpt; + if (description.length > 140 ) { + description = `${description.substr(0,description.substr(0,136).lastIndexOf(' '))}...`; + console.log('ici.'); + } + } + + const meta = [ + { name: 'description', content: description }, + { property: 'og:title', content: post.content.og_title }, + { property: 'og:description', content: post.content.og_description }, + { property: 'og:image', content: imageUrl }, + ]; + + this._setMeta(meta); + this._setTitle(post.content.meta_title); + } + + setDatasetSEO(data: Metadata) + { + const imageUrl = (data.image != null) ? + data.image.url : this._defaultImg; + + const description = data.abstractTroncated; + + const meta = [ + { name: 'description', content: description }, + { property: 'og:title', content: data.title }, + { property: 'og:description', content: description}, + { property: 'og:image', content: imageUrl }, + ]; + + this._setMeta(meta); + this._setTitle(data.title); + } + + setRoutingSEO(title:string) + { + if (title=='') { + title=pageTitles.home; + } + + const meta = [ + { name: 'description', content: this._defaultDesc }, + { property: 'og:title', content: title }, + { property: 'og:description', content: this._defaultDesc }, + { property: 'og:image', content: this._defaultImg } + ]; + this._setMeta(meta); + this._titleService.setTitle(title); + } + + setReuseSEO (reuse: Reuse) + { + const title:string = reuse.name; + const meta = [ + { name: 'description', content: '' }, + { property: 'og:title', content: title }, + { property: 'og:description', content: '' }, + { property: 'og:image', content: reuse.logo } + ]; + + this._setTitle(title); + this._setMeta(meta); + } + + private _setTitle(title:string) { + this._titleService.setTitle(`${title} - ${AppRoutes.root.title[this._lang]}` ); + } + + private _setMeta(metatags:{name?: string, property?:string, content:string}[]) { + + metatags.forEach((meta) => { + if (meta.content!= null) { + meta.content = meta.content.replace('\n', ' '); + this._metaService.updateTag(meta); + } + }); + } + +} diff --git a/src/app/elasticsearch/models/elasticsearch-options.model.ts b/src/app/elasticsearch/models/elasticsearch-options.model.ts index c3995f42eb2d278ad53136ec739d6d402042555e..34daf5bd04640174b788f2dd79ab7660421519d1 100644 --- a/src/app/elasticsearch/models/elasticsearch-options.model.ts +++ b/src/app/elasticsearch/models/elasticsearch-options.model.ts @@ -1,5 +1,5 @@ import { geosource } from '../../../i18n/traductions'; -import { scopesResearch } from '../../shared/variables'; +import { scopesResearch, isRentertron } from '../../shared/variables'; import { Filter } from './filter.model'; import { ISortOption } from './sort-option.model'; @@ -69,10 +69,13 @@ export class ElasticsearchOptions { value: (data && data.searchString != null) ? 'relevance' : 'date', order: 'desc', }; - if (data && data.sortOptions != null) { - this._sortOptions.value = data.sortOptions.value; - this._sortOptions.order = data.sortOptions.order; + if (isRentertron) { + this._sortOptions = { + value: 'alphabetical', + order: 'asc', + }; } + this._filters = (data && data.filters != null) ? data.filters : [ new Filter({ field: 'metadata-fr.category', @@ -156,6 +159,10 @@ export class ElasticsearchOptions { this._sortOptions.value = data.sortOptions.value; this._sortOptions.order = data.sortOptions.order; } + if (data && data.sortOptions != null) { + this._sortOptions.value = data.sortOptions.value; + this._sortOptions.order = data.sortOptions.order; + } } // Known licences diff --git a/src/app/routes.ts b/src/app/routes.ts index 4cf6ad64181cb06e21bea359d0c8ddbfe62c1363..23fe177bdaa81cb44b73800141e712d611e600f9 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -78,7 +78,7 @@ export const AppRoutes = { }, }, home: { - uri: 'accueil', + uri: '', title: { fr: 'Accueil', en: 'Home', @@ -168,13 +168,6 @@ export const AppRoutes = { en: 'Legal notices', }, }, - articles: { - uri: 'articles', - title: { - fr: 'Articles', - en: 'Articles', - }, - }, drafts: { uri: 'brouillons', title: { @@ -192,8 +185,8 @@ export const AppRoutes = { datasets: { uri: 'jeux-de-donnees', title: { - fr: 'Jeux de données', - en: 'Datasets', + fr: 'Jeux de données de la plateforme data de la Métropole de Lyon', + en: 'Data sets from the Metropole de Lyon data platform', }, }, info: { @@ -245,6 +238,13 @@ export const AppRoutes = { en: 'Reuses', }, }, + news: { + uri: 'actualites', + title: { + fr: 'Actualités de la plateforme data de la Métropole de Lyon', + en: 'News from the Metropole de Lyon data platform' + } + }, reusesDetail: { uri: 'reutilisations/:id', title: { diff --git a/src/app/shared/components/paginator/paginator.component.html b/src/app/shared/components/paginator/paginator.component.html index 5eaec45da83dab3e85280fa4bf23f9b1641c5bd0..4159e7ad1c3a4ebbbd93a80785c5766253eea2ab 100644 --- a/src/app/shared/components/paginator/paginator.component.html +++ b/src/app/shared/components/paginator/paginator.component.html @@ -31,11 +31,13 @@ <ul> <ng-container *ngFor="let pageNum of getPages(); let i = index"> <li> - <button *ngIf="!loading; else pageNumberDisabled" - [attr.aria-label]="pageNum" - (click)="onPage(pageNum)" class="button" - [ngClass]="{'is-current': pageNum === pageIndex}" - [attr.aria-current]="pageNum === pageIndex ? 'page' : undefined">{{ pageNum }}</button> + <a *ngIf="!loading; else pageNumberDisabled" + [attr.aria-label]="pageNum" + (click)="onPage(pageNum);" class="button" + href="{{ currentUrl }}?page={{ pageNum }}" + [ngClass]="{'is-current': pageNum === pageIndex}" + [attr.aria-current]="pageNum === pageIndex ? 'page' : undefined">{{ pageNum }}</a> + <ng-template #pageNumberDisabled> <button class="button" [ngClass]="{'is-current': pageNum === pageIndex}" [attr.aria-current]="pageNum === pageIndex ? 'page' : undefined" disabled>{{ pageNum }}</button> diff --git a/src/app/shared/components/paginator/paginator.component.ts b/src/app/shared/components/paginator/paginator.component.ts index 0debb3cfb0985ef9dcbd7c8d8542880645b099d7..2b2750f837ad9f3d9d28d9d3c74702617e16b1ce 100644 --- a/src/app/shared/components/paginator/paginator.component.ts +++ b/src/app/shared/components/paginator/paginator.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { ViewportScroller } from '@angular/common'; +import { Router } from '@angular/router'; @Component({ selector: 'app-paginator', @@ -20,12 +21,16 @@ export class PaginatorComponent implements OnInit { @Output() pageSizeChanged = new EventEmitter<number>(); pageSizeDropdownToggle = false; + currentUrl: string; constructor( private _viewportScroller: ViewportScroller, + private _router: Router ) { } ngOnInit() { + const url = this._router.url.split('?'); + this.currentUrl = url[0]; } onPrev() { @@ -42,9 +47,11 @@ export class PaginatorComponent implements OnInit { } } - onPage(n: number): void { + onPage(n: number): boolean { this.scrollTop(); this.page.emit(n); + + return false; } totalPages(): number { diff --git a/src/app/shared/variables.ts b/src/app/shared/variables.ts index 44819e091cc00268884ed2836cabd51a5b5613fb..e0cc28cc8faf24b14e1278fbf8d3978cf4994da0 100644 --- a/src/app/shared/variables.ts +++ b/src/app/shared/variables.ts @@ -1,10 +1,12 @@ import { geosource } from '../../i18n/traductions'; +export const isRentertron = /HeadlessChrome\//i.test(window.navigator.userAgent); + export const scopesResearch = { all: { key: 'all', label: geosource.researchScope.all, - elasticType: ['dataset', 'nonGeographicDataset', 'series', 'nonGeographicSeries','service','post'], + elasticType: ['dataset', 'nonGeographicDataset', 'series', 'nonGeographicSeries','service'], errorItem: geosource.errorItem.all, }, datasets: diff --git a/src/i18n/messages.en.xlf b/src/i18n/messages.en.xlf index 0675c6cb11033ef01cf6edb3048362fc9030f386..10c073043b0a01c65f47946b956465c7991c9e4c 100644 --- a/src/i18n/messages.en.xlf +++ b/src/i18n/messages.en.xlf @@ -23,6 +23,14 @@ <source>Research</source> <target>Research</target> </trans-unit> + <trans-unit id="menu.datasets" datatype="html"> + <source>Datasets</source> + <target>Datasets</target> + </trans-unit> + <trans-unit id="menu.news" datatype="html"> + <source>News</source> + <target>News</target> + </trans-unit> <trans-unit id="menu.approach" datatype="html"> <source>Approach</source> <target>Approach</target> @@ -1160,9 +1168,13 @@ Here is the list of the last evolutions of the portal. If you wish to contribute <source>Home</source> <target>Home</target> </trans-unit> - <trans-unit id="sitemap.research" datatype="html"> - <source>Research</source> - <target>Research</target> + <trans-unit id="sitemap.datasets" datatype="html"> + <source>Datasets</source> + <target>Datasets</target> + </trans-unit> + <trans-unit id="sitemap.news" datatype="html"> + <source>News</source> + <target>News</target> </trans-unit> <trans-unit id="sitemap.partners" datatype="html"> <source>Partners</source> @@ -1204,6 +1216,10 @@ Here is the list of the last evolutions of the portal. If you wish to contribute <source>Terms of use</source> <target>Terms of use</target> </trans-unit> + <trans-unit id="sitemap.changelog" datatype="html"> + <source>Last changes</source> + <target>Last changes</target> + </trans-unit> <!-- Results page --> <trans-unit id="results.noresult.1" datatype="html"> diff --git a/src/i18n/messages.fr.xlf b/src/i18n/messages.fr.xlf index 0b38b39502594479850c7c47011a120a794bd8fc..e0ebf9df66d8613a0383e897c5664e0e6ec860ed 100644 --- a/src/i18n/messages.fr.xlf +++ b/src/i18n/messages.fr.xlf @@ -23,6 +23,14 @@ <source>Research</source> <target>Recherche</target> </trans-unit> + <trans-unit id="menu.datasets" datatype="html"> + <source>Dat sets</source> + <target>Jeux de données</target> + </trans-unit> + <trans-unit id="menu.news" datatype="html"> + <source>News</source> + <target>Actualités</target> + </trans-unit> <trans-unit id="menu.approach" datatype="html"> <source>Approach</source> <target>Démarche</target> @@ -1169,9 +1177,13 @@ Voici la liste des dernières évolutions du portail. Si vous souhaitez contribu <source>Home</source> <target>Accueil</target> </trans-unit> - <trans-unit id="sitemap.research" datatype="html"> - <source>Research</source> - <target>Recherche</target> + <trans-unit id="sitemap.datasets" datatype="html"> + <source>Datasets</source> + <target>Jeux de données</target> + </trans-unit> + <trans-unit id="sitemap.news" datatype="html"> + <source>News</source> + <target>Actualités</target> </trans-unit> <trans-unit id="sitemap.partners" datatype="html"> <source>Partners</source> @@ -1179,7 +1191,7 @@ Voici la liste des dernières évolutions du portail. Si vous souhaitez contribu </trans-unit> <trans-unit id="sitemap.approach" datatype="html"> <source>Approach</source> - <target>La démarche</target> + <target>Démarche</target> </trans-unit> <trans-unit id="sitemap.documentation" datatype="html"> <source>Documentation</source> @@ -1213,6 +1225,10 @@ Voici la liste des dernières évolutions du portail. Si vous souhaitez contribu <source>Terms of use</source> <target>Conditions générales d'utilisation</target> </trans-unit> + <trans-unit id="sitemap.changelog" datatype="html"> + <source>Last changes</source> + <target>Dernières évolutions</target> + </trans-unit> <!-- Results page --> <trans-unit id="results.noresult.1" datatype="html"> diff --git a/src/i18n/traductions.fr.ts b/src/i18n/traductions.fr.ts index aaf5439011fc14a2ce34f0d9ec264e6297e65efe..6db669f9bbaba7bed45d09cf8a320c41892ca9dc 100644 --- a/src/i18n/traductions.fr.ts +++ b/src/i18n/traductions.fr.ts @@ -217,9 +217,16 @@ export const geosource = { }, }; + export const metaDescription = { - home: 'Les données des acteurs du territoire de la Métropole de Lyon', - research: 'Explorer les jeux de données', + home: "La plateforme des données des acteurs du territoire de la Métropole de Lyon. Elle permet la recherche et l'utilisation des données ouvertes (open data).", + research: 'La plateforme data.grandlyon.com offre un accès à plusieurs centaines de jeux de données. Ils peuvent être recherchés par mots-clés, par filtres, et triés suivant différents critères.', + dataset: "Des métadonnées décrivent la donnée : contexte et origine, producteur, thématique, statistiques, conditions d'accès (API).", + news: 'La Métropole de Lyon vous informe en continu sur les données ouvertes (open data) sur le territoire et les services offerts par la plateforme data du Grand Lyon', +}; +export const introText = { + research: "La plateforme data.grandlyon.com offre un accès à plusieurs centaines de jeux de données. Recherchez-les grâce à la recherche par mot-clé et par filtres : partenaire producteur de la donnée, thématique (environnement, transport…), format… Et explorez-les en accédant à leur page détaillée : cartographie, tableau textuel des données, description, lien de téléchargement et accès par API.", + news: "La Métropole de Lyon vous informe des dernières actualités de sa plateforme de données : ouverture de nouveaux jeux de données disponibles pour le territoire, exemples d'utilisation, dossiers thématiques en lien avec les jeux de données publiés, focus sur les partenaires de la donnée du Grand Lyon, événements, nouvelles fonctionnalités de la plateforme..." }; export const subjects = [ @@ -254,7 +261,9 @@ export const subjects = [ ]; export const pageTitles = { + home: 'data.granlyon.com : Open data de la Métropole de Lyon', siteMap: 'Plan du site', + datasets: 'Jeux de données', credits: 'Crédits', partners: 'Partenaires', changelog: 'Dernières évolutions', @@ -272,6 +281,7 @@ export const pageTitles = { userPasswordUpdate: 'Modifier mon mot de passe', contribution: 'Publier un jeu de données', reuses: 'Réutilisations', + news: 'Actualités', }; export const datatsetDataRepresentationType = { diff --git a/src/i18n/traductions.ts b/src/i18n/traductions.ts index 1c5f7be1ee51d2f8ccbff8434631499b6cdd8134..a91816d382a170681ce43fc63e5ef4f1424fc6d5 100644 --- a/src/i18n/traductions.ts +++ b/src/i18n/traductions.ts @@ -219,9 +219,16 @@ export const geosource = { }, }; + export const metaDescription = { - home: 'Data of the stakeholders of the Lyon Metropolitan Area', - research: 'Explore the datasets', + home: 'The data platform of the partners of the Metropole de Lyon territory. It allows the search and use of open data.', + research: 'The data.grandlyon.com platform offers access to several hundred datasets. They can be searched by keywords, by filters, and sorted according to different criteria.', + dataset: 'Metadata describe the data: context and origin, producer, subject, statistics, access conditions (API).', + news: 'The Metropole de Lyon informs you continuously about the open data on the territory and the services offered by the Greater Lyon data platform', +}; +export const introText = { + research: "The data.grandlyon.com platform offers access to several hundred data sets. Search for them using keywords and filters: data producing partner, theme (environment, transport, etc.), format, etc. And explore them by accessing their detailed page: cartography, textual table of data, description, download link and API access.", + news: "The Metropole de Lyon informs you about the latest news of its data platform: opening of new datasets available for the territory, examples of use, thematic files related to the published datasets, focus on the data partners of Greater Lyon, events, new features of the platform..." }; export const subjects = [ @@ -256,9 +263,12 @@ export const subjects = [ ]; export const pageTitles = { + home: 'data.granlyon.com : Open data of the Metropole de Lyon', siteMap: 'Site map', + datasets: 'Data sets', credits: 'Credits', partners: 'Partners', + news: 'News', changelog: 'Last changes', actors: 'Actors', signup: 'Sign up', diff --git a/src/index.html b/src/index.html index 62d295b779e79123e5795e8e00f1a7f45023412f..1dae88dd10667c81d162f3c1f42e5026ec3f9d3c 100644 --- a/src/index.html +++ b/src/index.html @@ -3,8 +3,8 @@ <head> <meta charset="utf-8"> - <title>Accueil - data.grandlyon.com</title> - <meta name="description" content="Les données des acteurs du territoire de la Métropole de Lyon"> + <title>data.grandlyon.com : Open data de la Métropole de Lyon</title> + <meta name="description" content="Basé entièrement sur des briques logicielles Open Source, ce portail vous invite à découvrir les données des acteurs du territoire de la Métropole de Lyon"> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1">