Skip to content

Commit a4ddc76

Browse files
committed
refactor: generate image with sharp and convert enum to const
1 parent ea996d0 commit a4ddc76

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+369
-262
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ excerpt: Description of the article (Visible on the list pages)
131131
cover:
132132
alt: Alt image
133133
path: /imgs/articles/YYYY-MM-DD-slug/cover.jpg
134+
position: top | right top | right | right bottom | bottom | left bottom | left | left top | center | north | northeast | east | southeast | south | southwest | west | northwest // Default value is center
134135
categories:
135136
- javascript | php | agile | architecture
136137
keywords:

_articles/fr/2024-02-19-quelques-conseils-pour-optimiser-votre-environnement-de-travail-sous-linux.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ excerpt: >-
99
categories: []
1010
cover:
1111
path: /imgs/articles/2024-02-19-quelques-conseils-pour-optimiser-votre-environnement-de-travail-sous-linux/cover.jpg
12+
position: top
1213
authors:
1314
- nicolas
1415
keywords:

_tutorials/fr/2024-03-27-chromatic/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ excerpt: >-
88
Nous allons découvrir comment utiliser Chromatic en CI pour faire des tests de non régression visuelle et des tests d'interaction sur un Storybook pour être confiant à chaque nouvelle feature implémentée.
99
cover:
1010
path: /imgs/tutorials/2024-03-27-chromatic/cover.jpg
11+
position: top
1112
categories:
1213
- javascript
1314
keywords:

src/config/i18n/i18n.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { InitOptions } from 'i18next';
22

3-
import { BASE_URL, DEFAULT_LANGUAGE, IS_DEBUG, LanguageEnum, LANGUAGES_AVAILABLE } from '@/constants';
3+
import { BASE_URL, DEFAULT_LANGUAGE, IS_DEBUG, LANGUAGES, LANGUAGES_AVAILABLE } from '@/constants';
44

55
export const i18nConfig = {
66
load: 'languageOnly',
77
preload: LANGUAGES_AVAILABLE,
88
whitelist: LANGUAGES_AVAILABLE,
9-
fallbackLng: IS_DEBUG ? LanguageEnum.DT : DEFAULT_LANGUAGE,
9+
fallbackLng: IS_DEBUG ? LANGUAGES.DT : DEFAULT_LANGUAGE,
1010
returnEmptyString: false,
1111
defaultNS: 'messages',
1212
ns: 'messages',

src/config/router/routes.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { Params, RouteObject } from 'react-router';
33
import { Outlet } from 'react-router-dom';
44

5-
import { LanguageEnum, LANGUAGES_AVAILABLE_WITH_DT, PATHS } from '@/constants';
5+
import { LANGUAGES_AVAILABLE_WITH_DT, PATHS } from '@/constants';
66
import { AuthorPageContainer } from '@/containers/AuthorPageContainer';
77
import { CategoryPageContainer } from '@/containers/CategoryPageContainer';
88
import { HomePageContainer } from '@/containers/HomePageContainer';
@@ -16,7 +16,7 @@ import {
1616
loadPostListPageData,
1717
loadPostPageData,
1818
} from '@/helpers/loaderDataHelper';
19-
import { LayoutTemplateData } from '@/types';
19+
import { LanguageType, LayoutTemplateData } from '@/types';
2020

2121
export const routes: RouteObject[] = [
2222
{
@@ -50,8 +50,8 @@ export const routes: RouteObject[] = [
5050
{
5151
path: '/:lang/',
5252
loader: ({ params }): Record<string, unknown> => {
53-
const languages = LANGUAGES_AVAILABLE_WITH_DT as LanguageEnum[];
54-
if (!languages.includes(params.lang as LanguageEnum)) {
53+
const languages = LANGUAGES_AVAILABLE_WITH_DT as LanguageType[];
54+
if (!languages.includes(params.lang as LanguageType)) {
5555
throw new Error(`The \`${params.lang}\` language doesn't exist`);
5656
}
5757
return {};

src/config/schemaValidation/AuthorDataValidationSchema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { z } from 'zod';
22

3-
import { ContentTypeEnum } from '@/constants';
3+
import { MARKDOWN_CONTENT_TYPES } from '@/constants';
44

55
export const AuthorDataValidationSchema = z.object({
6-
contentType: z.literal(ContentTypeEnum.AUTHOR),
6+
contentType: z.literal(MARKDOWN_CONTENT_TYPES.AUTHOR),
77
username: z.string().regex(/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/, 'Kebab case format not respected'),
88
name: z.string(),
99
twitter: z

src/config/schemaValidation/PostDataSchemaValidation.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { z } from 'zod';
22

3-
import { CATEGORIES, ContentTypeEnum, LanguageEnum } from '@/constants';
3+
import { CATEGORIES, IMAGE_POSITIONS, LANGUAGES, MARKDOWN_CONTENT_TYPES } from '@/constants';
44
import { intersection } from '@/helpers/objectHelper';
55

66
export const PostDataSchemaValidation = z.object({
7-
contentType: z.enum([ContentTypeEnum.ARTICLE, ContentTypeEnum.TUTORIAL]),
8-
lang: z.nativeEnum(LanguageEnum),
7+
contentType: z.nativeEnum({
8+
ARTICLE: MARKDOWN_CONTENT_TYPES.ARTICLE,
9+
TUTORIAL: MARKDOWN_CONTENT_TYPES.TUTORIAL,
10+
} as const),
11+
lang: z.nativeEnum(LANGUAGES),
912
date: z.coerce.date().transform((date) => date.toISOString().slice(0, 10)),
1013
slug: z.string().regex(/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/, 'Kebab case format not respected'),
1114
title: z.string(),
@@ -14,6 +17,7 @@ export const PostDataSchemaValidation = z.object({
1417
cover: z
1518
.object({
1619
path: z.string(),
20+
position: z.nativeEnum(IMAGE_POSITIONS).optional(),
1721
alt: z.string(),
1822
})
1923
.optional(),
@@ -48,13 +52,13 @@ export const PostDataSchemaValidation = z.object({
4852

4953
export const ArticleDataSchemaValidation = PostDataSchemaValidation.merge(
5054
z.object({
51-
contentType: z.literal(ContentTypeEnum.ARTICLE),
55+
contentType: z.literal(MARKDOWN_CONTENT_TYPES.ARTICLE),
5256
})
5357
);
5458

5559
export const TutorialDataSchemaValidation = PostDataSchemaValidation.merge(
5660
z.object({
57-
contentType: z.literal(ContentTypeEnum.TUTORIAL),
61+
contentType: z.literal(MARKDOWN_CONTENT_TYPES.TUTORIAL),
5862
steps: z.array(z.string()),
5963
})
6064
);

src/config/schemaValidation/TutorialStepDataValidationSchema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { z } from 'zod';
22

3-
import { ContentTypeEnum } from '@/constants';
3+
import { MARKDOWN_CONTENT_TYPES } from '@/constants';
44

55
export const TutorialStepDataValidationSchema = z.object({
6-
contentType: z.literal(ContentTypeEnum.TUTORIAL_STEP),
6+
contentType: z.literal(MARKDOWN_CONTENT_TYPES.TUTORIAL_STEP),
77
tutorial: z.string(),
88
slug: z.string(),
99
title: z.string(),

src/constants.ts

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getEnv } from '@/helpers/getEnvHelper';
2+
import { DeviceType, ImageExtensionType, ImageFormatType } from '@/types';
23

34
export const IS_SSR = import.meta.env?.SSR ?? false;
45
export const IS_PRERENDER = import.meta.env?.MODE === 'prerender';
@@ -7,26 +8,25 @@ export const BASE_URL = import.meta.env?.BASE_URL || '/';
78

89
export const IS_DEBUG = getEnv<string>('VITE_IS_DEBUG') === 'true';
910

10-
export enum LanguageEnum {
11-
FR = 'fr',
12-
EN = 'en',
13-
DT = 'dt',
14-
}
11+
export const LANGUAGES = {
12+
FR: 'fr',
13+
EN: 'en',
14+
DT: 'dt',
15+
} as const;
1516

16-
export const LANGUAGES_AVAILABLE = [LanguageEnum.FR, LanguageEnum.EN] as const;
17-
export const LANGUAGES_AVAILABLE_WITH_DT = IS_DEBUG ? [...LANGUAGES_AVAILABLE, LanguageEnum.DT] : LANGUAGES_AVAILABLE;
17+
export const LANGUAGES_AVAILABLE = [LANGUAGES.FR, LANGUAGES.EN] as const;
18+
export const LANGUAGES_AVAILABLE_WITH_DT = IS_DEBUG ? [...LANGUAGES_AVAILABLE, LANGUAGES.DT] : LANGUAGES_AVAILABLE;
1819

19-
export enum ContentTypeEnum {
20-
ARTICLE = 'article',
21-
TUTORIAL = 'tutorial',
22-
TUTORIAL_STEP = 'tutorial-step',
23-
AUTHOR = 'author',
24-
}
20+
export const MARKDOWN_CONTENT_TYPES = {
21+
ARTICLE: 'article',
22+
TUTORIAL: 'tutorial',
23+
TUTORIAL_STEP: 'tutorial-step',
24+
AUTHOR: 'author',
25+
} as const;
2526

2627
export const CATEGORIES = ['javascript', 'php', 'agile', 'architecture'] as const;
27-
export type CategoryEnum = (typeof CATEGORIES)[number];
2828

29-
export const DEFAULT_LANGUAGE = LanguageEnum.FR;
29+
export const DEFAULT_LANGUAGE = LANGUAGES.FR;
3030
export const NUMBER_OF_ITEMS_FOR_SEARCH = 6;
3131
export const NUMBER_OF_ITEMS_PER_PAGE = 12;
3232

@@ -51,53 +51,83 @@ export const GTM_ID = getEnv<string>('VITE_GTM_ID');
5151

5252
export const GOOGLE_SITE_VERIFICATION = getEnv<string>('VITE_GOOGLE_SITE_VERIFICATION');
5353

54-
export enum ImageFormatEnum {
55-
HIGHLIGHTED_ARTICLE_POST_CARD_COVER = 'highlighted-article-post-card-cover',
56-
HIGHLIGHTED_TUTORIAL_POST_CARD_COVER = 'highlighted-tutorial-post-card-cover',
57-
POST_CARD_COVER = 'post-card-cover',
58-
POST_COVER = 'post-cover',
59-
}
60-
61-
export enum DeviceEnum {
62-
MOBILE = 'mobile',
63-
DESKTOP = 'desktop',
64-
}
65-
66-
export const IMAGE_FORMATS: Record<DeviceEnum, Record<ImageFormatEnum, { width: number; height: number }>> = {
67-
mobile: {
68-
[ImageFormatEnum.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
69-
width: 67,
70-
height: 67,
71-
},
72-
[ImageFormatEnum.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
73-
width: 328,
74-
height: 130,
75-
},
76-
[ImageFormatEnum.POST_CARD_COVER]: {
77-
width: 67,
78-
height: 67,
79-
},
80-
[ImageFormatEnum.POST_COVER]: {
81-
width: 330,
82-
height: 160,
83-
},
84-
},
85-
desktop: {
86-
[ImageFormatEnum.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
54+
export const IMAGE_FORMATS = {
55+
HIGHLIGHTED_ARTICLE_POST_CARD_COVER: 'highlighted-article-post-card-cover',
56+
HIGHLIGHTED_TUTORIAL_POST_CARD_COVER: 'highlighted-tutorial-post-card-cover',
57+
POST_CARD_COVER: 'post-card-cover',
58+
POST_COVER: 'post-cover',
59+
} as const;
60+
61+
export const DEVICES = {
62+
DESKTOP: 'desktop',
63+
MOBILE: 'mobile',
64+
} as const;
65+
66+
export const IMAGE_CONTENT_TYPES = {
67+
jpeg: 'image/jpeg',
68+
gif: 'image/gif',
69+
webp: 'image/webp',
70+
png: 'image/png',
71+
avif: 'image/avif',
72+
} as const;
73+
74+
export const IMAGE_POSITIONS = {
75+
TOP: 'top',
76+
RIGHT_AND_TOP: 'right top',
77+
RIGHT: 'right',
78+
RIGHT_BOTTOM: 'right bottom',
79+
BOTTOM: 'bottom',
80+
LEFT_AND_BOTTOM: 'left bottom',
81+
LEFT: 'left',
82+
LEFT_TOP: 'left top',
83+
CENTER: 'center',
84+
NORTH: 'north',
85+
NORTHEAST: 'northeast',
86+
EAST: 'east',
87+
SOUTHEAST: 'southeast',
88+
SOUTH: 'south',
89+
SOUTHWEST: 'southwest',
90+
WEST: 'west',
91+
NORTHWEST: 'northwest',
92+
} as const;
93+
94+
export const DEFAULT_EXTENSION_FOR_IMAGES: ImageExtensionType = 'avif';
95+
96+
export const SIZES_BY_IMAGE_FORMAT: Record<DeviceType, Record<ImageFormatType, { width: number; height: number }>> = {
97+
[DEVICES.DESKTOP]: {
98+
[IMAGE_FORMATS.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
8799
width: 385,
88100
height: 175,
89101
},
90-
[ImageFormatEnum.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
102+
[IMAGE_FORMATS.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
91103
width: 400,
92104
height: 245,
93105
},
94-
[ImageFormatEnum.POST_CARD_COVER]: {
106+
[IMAGE_FORMATS.POST_CARD_COVER]: {
95107
width: 190,
96108
height: 190,
97109
},
98-
[ImageFormatEnum.POST_COVER]: {
110+
[IMAGE_FORMATS.POST_COVER]: {
99111
width: 1200,
100112
height: 330,
101113
},
102114
},
115+
[DEVICES.MOBILE]: {
116+
[IMAGE_FORMATS.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
117+
width: 67,
118+
height: 67,
119+
},
120+
[IMAGE_FORMATS.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
121+
width: 328,
122+
height: 130,
123+
},
124+
[IMAGE_FORMATS.POST_CARD_COVER]: {
125+
width: 67,
126+
height: 67,
127+
},
128+
[IMAGE_FORMATS.POST_COVER]: {
129+
width: 330,
130+
height: 160,
131+
},
132+
},
103133
} as const;

src/containers/ArticlePageContainer/useArticlePageContainer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Box, PostPageProps } from '@eleven-labs/design-system';
22
import React from 'react';
33
import { useTranslation } from 'react-i18next';
44

5-
import { ContentTypeEnum } from '@/constants';
5+
import { MARKDOWN_CONTENT_TYPES } from '@/constants';
66
import { slugify } from '@/helpers/stringHelper';
77
import { usePostPage } from '@/hooks/usePostPage';
88
import { ArticlePageData } from '@/types';
@@ -12,7 +12,7 @@ export const useArticlePageContainer = (article: ArticlePageData): PostPageProps
1212
const postPage = usePostPage(article);
1313

1414
return {
15-
variant: ContentTypeEnum.ARTICLE,
15+
variant: MARKDOWN_CONTENT_TYPES.ARTICLE,
1616
...postPage,
1717
summary: {
1818
title: t('pages.article.summary_card.title'),

src/containers/CategoryPageContainer/useCategoryPageContainer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
55
import { useLoaderData, useParams } from 'react-router-dom';
66

77
import { blogUrl } from '@/config/website';
8-
import { ContentTypeEnum, DEFAULT_LANGUAGE, PATHS } from '@/constants';
8+
import { DEFAULT_LANGUAGE, MARKDOWN_CONTENT_TYPES, PATHS } from '@/constants';
99
import { PostCardListContainer, PostCardListContainerProps } from '@/containers/PostCardListContainer';
1010
import { TransWithHtml } from '@/containers/TransWithHtml';
1111
import { generatePath } from '@/helpers/routerHelper';
@@ -40,7 +40,7 @@ export const useCategoryPageContainer = (): CategoryPageProps => {
4040
title: <TransWithHtml i18nKey={`pages.category.${categoryName}.title`} onlyLineBreak />,
4141
description: <TransWithHtml i18nKey={`pages.category.${categoryName}.description`} />,
4242
},
43-
categoryEndingBlock: !['all', ContentTypeEnum.TUTORIAL].includes(categoryName as string)
43+
categoryEndingBlock: !['all', MARKDOWN_CONTENT_TYPES.TUTORIAL].includes(categoryName as string)
4444
? {
4545
title: <TransWithHtml i18nKey={`pages.category.${categoryName}.expertise.title`} onlyLineBreak />,
4646
description: <TransWithHtml i18nKey={`pages.category.${categoryName}.expertise.description`} />,

src/containers/HomePageContainer/useHomePageContainer.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
55
import { useLoaderData } from 'react-router-dom';
66

77
import { blogUrl, websiteUrl } from '@/config/website';
8-
import { ContentTypeEnum, DEFAULT_LANGUAGE, ImageFormatEnum, LanguageEnum, PATHS } from '@/constants';
8+
import { DEFAULT_LANGUAGE, IMAGE_FORMATS, LANGUAGES, MARKDOWN_CONTENT_TYPES, PATHS } from '@/constants';
99
import { TransWithHtml } from '@/containers/TransWithHtml';
1010
import { generatePath } from '@/helpers/routerHelper';
1111
import { useNewsletterCard } from '@/hooks/useNewsletterCard';
@@ -22,21 +22,21 @@ export const useHomePageContainer = (): HomePageProps => {
2222
posts: postListPageData.posts
2323
.filter(
2424
(post) =>
25-
post.contentType === ContentTypeEnum.ARTICLE &&
26-
(i18n.language === LanguageEnum.DT || post.lang === i18n.language)
25+
post.contentType === MARKDOWN_CONTENT_TYPES.ARTICLE &&
26+
(i18n.language === LANGUAGES.DT || post.lang === i18n.language)
2727
)
2828
.slice(0, 3),
29-
imageFormatEnum: ImageFormatEnum.HIGHLIGHTED_ARTICLE_POST_CARD_COVER,
29+
imageFormat: IMAGE_FORMATS.HIGHLIGHTED_ARTICLE_POST_CARD_COVER,
3030
});
3131
const lastTutorialsForCardList = usePostsForCardList({
3232
posts: postListPageData.posts
3333
.filter(
3434
(post) =>
35-
post.contentType === ContentTypeEnum.TUTORIAL &&
36-
(i18n.language === LanguageEnum.DT || post.lang === i18n.language)
35+
post.contentType === MARKDOWN_CONTENT_TYPES.TUTORIAL &&
36+
(i18n.language === LANGUAGES.DT || post.lang === i18n.language)
3737
)
3838
.slice(0, 2),
39-
imageFormatEnum: ImageFormatEnum.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER,
39+
imageFormat: IMAGE_FORMATS.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER,
4040
});
4141

4242
useTitle(t('pages.home.seo.title'));
@@ -73,7 +73,7 @@ export const useHomePageContainer = (): HomePageProps => {
7373
posts: lastTutorialsForCardList,
7474
linkSeeMore: {
7575
label: t('pages.home.last-tutorials-block.link-see-more'),
76-
href: generatePath(PATHS.CATEGORY, { categoryName: ContentTypeEnum.TUTORIAL, lang: i18n.language }),
76+
href: generatePath(PATHS.CATEGORY, { categoryName: MARKDOWN_CONTENT_TYPES.TUTORIAL, lang: i18n.language }),
7777
},
7878
}
7979
: undefined,

src/containers/PostCardListContainer/usePostCardListContainer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PostCardListProps } from '@eleven-labs/design-system';
22

3-
import { ImageFormatEnum, NUMBER_OF_ITEMS_PER_PAGE } from '@/constants';
3+
import { IMAGE_FORMATS, NUMBER_OF_ITEMS_PER_PAGE } from '@/constants';
44
import { usePostsForCardList } from '@/hooks/usePostsForCardList';
55

66
import { PostCardListContainerProps } from './PostCardListContainer';
@@ -20,7 +20,7 @@ export const usePostCardListContainer = ({
2020
isLoading,
2121
numberOfItems: NUMBER_OF_ITEMS_PER_PAGE,
2222
posts,
23-
imageFormatEnum: ImageFormatEnum.POST_CARD_COVER,
23+
imageFormat: IMAGE_FORMATS.POST_CARD_COVER,
2424
});
2525

2626
return {

0 commit comments

Comments
 (0)