Skip to content

Commit

Permalink
refactor: generate image with sharp and convert enum to const
Browse files Browse the repository at this point in the history
  • Loading branch information
fpasquet committed Apr 15, 2024
1 parent ea996d0 commit 091cc3c
Show file tree
Hide file tree
Showing 42 changed files with 368 additions and 261 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -131,6 +131,7 @@ excerpt: Description of the article (Visible on the list pages)
cover:
alt: Alt image
path: /imgs/articles/YYYY-MM-DD-slug/cover.jpg
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
categories:
- javascript | php | agile | architecture
keywords:
Expand Down
Expand Up @@ -9,6 +9,7 @@ excerpt: >-
categories: []
cover:
path: /imgs/articles/2024-02-19-quelques-conseils-pour-optimiser-votre-environnement-de-travail-sous-linux/cover.jpg
position: top
authors:
- nicolas
keywords:
Expand Down
1 change: 1 addition & 0 deletions _tutorials/fr/2024-03-27-chromatic/index.md
Expand Up @@ -8,6 +8,7 @@ excerpt: >-
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.
cover:
path: /imgs/tutorials/2024-03-27-chromatic/cover.jpg
position: top
categories:
- javascript
keywords:
Expand Down
4 changes: 2 additions & 2 deletions src/config/i18n/i18n.config.ts
@@ -1,12 +1,12 @@
import { InitOptions } from 'i18next';

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

export const i18nConfig = {
load: 'languageOnly',
preload: LANGUAGES_AVAILABLE,
whitelist: LANGUAGES_AVAILABLE,
fallbackLng: IS_DEBUG ? LanguageEnum.DT : DEFAULT_LANGUAGE,
fallbackLng: IS_DEBUG ? LANGUAGES.DT : DEFAULT_LANGUAGE,
returnEmptyString: false,
defaultNS: 'messages',
ns: 'messages',
Expand Down
8 changes: 4 additions & 4 deletions src/config/router/routes.tsx
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { Params, RouteObject } from 'react-router';
import { Outlet } from 'react-router-dom';

import { LanguageEnum, LANGUAGES_AVAILABLE_WITH_DT, PATHS } from '@/constants';
import { LANGUAGES_AVAILABLE_WITH_DT, PATHS } from '@/constants';
import { AuthorPageContainer } from '@/containers/AuthorPageContainer';
import { CategoryPageContainer } from '@/containers/CategoryPageContainer';
import { HomePageContainer } from '@/containers/HomePageContainer';
Expand All @@ -16,7 +16,7 @@ import {
loadPostListPageData,
loadPostPageData,
} from '@/helpers/loaderDataHelper';
import { LayoutTemplateData } from '@/types';
import { LanguageType, LayoutTemplateData } from '@/types';

export const routes: RouteObject[] = [
{
Expand Down Expand Up @@ -50,8 +50,8 @@ export const routes: RouteObject[] = [
{
path: '/:lang/',
loader: ({ params }): Record<string, unknown> => {
const languages = LANGUAGES_AVAILABLE_WITH_DT as LanguageEnum[];
if (!languages.includes(params.lang as LanguageEnum)) {
const languages = LANGUAGES_AVAILABLE_WITH_DT as LanguageType[];
if (!languages.includes(params.lang as LanguageType)) {
throw new Error(`The \`${params.lang}\` language doesn't exist`);
}
return {};
Expand Down
4 changes: 2 additions & 2 deletions src/config/schemaValidation/AuthorDataValidationSchema.ts
@@ -1,9 +1,9 @@
import { z } from 'zod';

import { ContentTypeEnum } from '@/constants';
import { MARKDOWN_CONTENT_TYPES } from '@/constants';

export const AuthorDataValidationSchema = z.object({
contentType: z.literal(ContentTypeEnum.AUTHOR),
contentType: z.literal(MARKDOWN_CONTENT_TYPES.AUTHOR),
username: z.string().regex(/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/, 'Kebab case format not respected'),
name: z.string(),
twitter: z
Expand Down
14 changes: 9 additions & 5 deletions src/config/schemaValidation/PostDataSchemaValidation.ts
@@ -1,11 +1,14 @@
import { z } from 'zod';

import { CATEGORIES, ContentTypeEnum, LanguageEnum } from '@/constants';
import { CATEGORIES, IMAGE_POSITIONS, LANGUAGES, MARKDOWN_CONTENT_TYPES } from '@/constants';
import { intersection } from '@/helpers/objectHelper';

export const PostDataSchemaValidation = z.object({
contentType: z.enum([ContentTypeEnum.ARTICLE, ContentTypeEnum.TUTORIAL]),
lang: z.nativeEnum(LanguageEnum),
contentType: z.nativeEnum({
ARTICLE: MARKDOWN_CONTENT_TYPES.ARTICLE,
TUTORIAL: MARKDOWN_CONTENT_TYPES.TUTORIAL,
} as const),
lang: z.nativeEnum(LANGUAGES),
date: z.coerce.date().transform((date) => date.toISOString().slice(0, 10)),
slug: z.string().regex(/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/, 'Kebab case format not respected'),
title: z.string(),
Expand All @@ -14,6 +17,7 @@ export const PostDataSchemaValidation = z.object({
cover: z
.object({
path: z.string(),
position: z.nativeEnum(IMAGE_POSITIONS).optional(),
alt: z.string(),
})
.optional(),
Expand Down Expand Up @@ -48,13 +52,13 @@ export const PostDataSchemaValidation = z.object({

export const ArticleDataSchemaValidation = PostDataSchemaValidation.merge(
z.object({
contentType: z.literal(ContentTypeEnum.ARTICLE),
contentType: z.literal(MARKDOWN_CONTENT_TYPES.ARTICLE),
})
);

export const TutorialDataSchemaValidation = PostDataSchemaValidation.merge(
z.object({
contentType: z.literal(ContentTypeEnum.TUTORIAL),
contentType: z.literal(MARKDOWN_CONTENT_TYPES.TUTORIAL),
steps: z.array(z.string()),
})
);
@@ -1,9 +1,9 @@
import { z } from 'zod';

import { ContentTypeEnum } from '@/constants';
import { MARKDOWN_CONTENT_TYPES } from '@/constants';

export const TutorialStepDataValidationSchema = z.object({
contentType: z.literal(ContentTypeEnum.TUTORIAL_STEP),
contentType: z.literal(MARKDOWN_CONTENT_TYPES.TUTORIAL_STEP),
tutorial: z.string(),
slug: z.string(),
title: z.string(),
Expand Down
132 changes: 81 additions & 51 deletions src/constants.ts
@@ -1,4 +1,5 @@
import { getEnv } from '@/helpers/getEnvHelper';
import { DeviceType, ImageExtensionType, ImageFormatType } from '@/types';

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

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

export enum LanguageEnum {
FR = 'fr',
EN = 'en',
DT = 'dt',
}
export const LANGUAGES = {
FR: 'fr',
EN: 'en',
DT: 'dt',
} as const;

export const LANGUAGES_AVAILABLE = [LanguageEnum.FR, LanguageEnum.EN] as const;
export const LANGUAGES_AVAILABLE_WITH_DT = IS_DEBUG ? [...LANGUAGES_AVAILABLE, LanguageEnum.DT] : LANGUAGES_AVAILABLE;
export const LANGUAGES_AVAILABLE = [LANGUAGES.FR, LANGUAGES.EN] as const;
export const LANGUAGES_AVAILABLE_WITH_DT = IS_DEBUG ? [...LANGUAGES_AVAILABLE, LANGUAGES.DT] : LANGUAGES_AVAILABLE;

export enum ContentTypeEnum {
ARTICLE = 'article',
TUTORIAL = 'tutorial',
TUTORIAL_STEP = 'tutorial-step',
AUTHOR = 'author',
}
export const MARKDOWN_CONTENT_TYPES = {
ARTICLE: 'article',
TUTORIAL: 'tutorial',
TUTORIAL_STEP: 'tutorial-step',
AUTHOR: 'author',
} as const;

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

export const DEFAULT_LANGUAGE = LanguageEnum.FR;
export const DEFAULT_LANGUAGE = LANGUAGES.FR;
export const NUMBER_OF_ITEMS_FOR_SEARCH = 6;
export const NUMBER_OF_ITEMS_PER_PAGE = 12;

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

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

export enum ImageFormatEnum {
HIGHLIGHTED_ARTICLE_POST_CARD_COVER = 'highlighted-article-post-card-cover',
HIGHLIGHTED_TUTORIAL_POST_CARD_COVER = 'highlighted-tutorial-post-card-cover',
POST_CARD_COVER = 'post-card-cover',
POST_COVER = 'post-cover',
}

export enum DeviceEnum {
MOBILE = 'mobile',
DESKTOP = 'desktop',
}

export const IMAGE_FORMATS: Record<DeviceEnum, Record<ImageFormatEnum, { width: number; height: number }>> = {
mobile: {
[ImageFormatEnum.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
width: 67,
height: 67,
},
[ImageFormatEnum.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
width: 328,
height: 130,
},
[ImageFormatEnum.POST_CARD_COVER]: {
width: 67,
height: 67,
},
[ImageFormatEnum.POST_COVER]: {
width: 330,
height: 160,
},
},
desktop: {
[ImageFormatEnum.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
export const IMAGE_FORMATS = {
HIGHLIGHTED_ARTICLE_POST_CARD_COVER: 'highlighted-article-post-card-cover',
HIGHLIGHTED_TUTORIAL_POST_CARD_COVER: 'highlighted-tutorial-post-card-cover',
POST_CARD_COVER: 'post-card-cover',
POST_COVER: 'post-cover',
} as const;

export const DEVICES = {
DESKTOP: 'desktop',
MOBILE: 'mobile',
} as const;

export const IMAGE_CONTENT_TYPES = {
jpeg: 'image/jpeg',
gif: 'image/gif',
webp: 'image/webp',
png: 'image/png',
avif: 'image/avif',
} as const;

export const IMAGE_POSITIONS = {
TOP: 'top',
RIGHT_AND_TOP: 'right top',
RIGHT: 'right',
RIGHT_BOTTOM: 'right bottom',
BOTTOM: 'bottom',
LEFT_AND_BOTTOM: 'left bottom',
LEFT: 'left',
LEFT_TOP: 'left top',
CENTER: 'center',
NORTH: 'north',
NORTHEAST: 'northeast',
EAST: 'east',
SOUTHEAST: 'southeast',
SOUTH: 'south',
SOUTHWEST: 'southwest',
WEST: 'west',
NORTHWEST: 'northwest',
} as const;

export const DEFAULT_EXTENSION_FOR_IMAGES: ImageExtensionType = 'avif';

export const SIZES_BY_IMAGE_FORMAT: Record<DeviceType, Record<ImageFormatType, { width: number; height: number }>> = {
[DEVICES.DESKTOP]: {
[IMAGE_FORMATS.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
width: 385,
height: 175,
},
[ImageFormatEnum.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
[IMAGE_FORMATS.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
width: 400,
height: 245,
},
[ImageFormatEnum.POST_CARD_COVER]: {
[IMAGE_FORMATS.POST_CARD_COVER]: {
width: 190,
height: 190,
},
[ImageFormatEnum.POST_COVER]: {
[IMAGE_FORMATS.POST_COVER]: {
width: 1200,
height: 330,
},
},
[DEVICES.MOBILE]: {
[IMAGE_FORMATS.HIGHLIGHTED_ARTICLE_POST_CARD_COVER]: {
width: 67,
height: 67,
},
[IMAGE_FORMATS.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER]: {
width: 328,
height: 130,
},
[IMAGE_FORMATS.POST_CARD_COVER]: {
width: 67,
height: 67,
},
[IMAGE_FORMATS.POST_COVER]: {
width: 330,
height: 160,
},
},
} as const;
Expand Up @@ -2,7 +2,7 @@ import { Box, PostPageProps } from '@eleven-labs/design-system';
import React from 'react';
import { useTranslation } from 'react-i18next';

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

return {
variant: ContentTypeEnum.ARTICLE,
variant: MARKDOWN_CONTENT_TYPES.ARTICLE,
...postPage,
summary: {
title: t('pages.article.summary_card.title'),
Expand Down
Expand Up @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
import { useLoaderData, useParams } from 'react-router-dom';

import { blogUrl } from '@/config/website';
import { ContentTypeEnum, DEFAULT_LANGUAGE, PATHS } from '@/constants';
import { DEFAULT_LANGUAGE, MARKDOWN_CONTENT_TYPES, PATHS } from '@/constants';
import { PostCardListContainer, PostCardListContainerProps } from '@/containers/PostCardListContainer';
import { TransWithHtml } from '@/containers/TransWithHtml';
import { generatePath } from '@/helpers/routerHelper';
Expand Down Expand Up @@ -40,7 +40,7 @@ export const useCategoryPageContainer = (): CategoryPageProps => {
title: <TransWithHtml i18nKey={`pages.category.${categoryName}.title`} onlyLineBreak />,
description: <TransWithHtml i18nKey={`pages.category.${categoryName}.description`} />,
},
categoryEndingBlock: !['all', ContentTypeEnum.TUTORIAL].includes(categoryName as string)
categoryEndingBlock: !['all', MARKDOWN_CONTENT_TYPES.TUTORIAL].includes(categoryName as string)
? {
title: <TransWithHtml i18nKey={`pages.category.${categoryName}.expertise.title`} onlyLineBreak />,
description: <TransWithHtml i18nKey={`pages.category.${categoryName}.expertise.description`} />,
Expand Down
16 changes: 8 additions & 8 deletions src/containers/HomePageContainer/useHomePageContainer.tsx
Expand Up @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
import { useLoaderData } from 'react-router-dom';

import { blogUrl, websiteUrl } from '@/config/website';
import { ContentTypeEnum, DEFAULT_LANGUAGE, ImageFormatEnum, LanguageEnum, PATHS } from '@/constants';
import { DEFAULT_LANGUAGE, IMAGE_FORMATS, LANGUAGES, MARKDOWN_CONTENT_TYPES, PATHS } from '@/constants';
import { TransWithHtml } from '@/containers/TransWithHtml';
import { generatePath } from '@/helpers/routerHelper';
import { useNewsletterCard } from '@/hooks/useNewsletterCard';
Expand All @@ -22,21 +22,21 @@ export const useHomePageContainer = (): HomePageProps => {
posts: postListPageData.posts
.filter(
(post) =>
post.contentType === ContentTypeEnum.ARTICLE &&
(i18n.language === LanguageEnum.DT || post.lang === i18n.language)
post.contentType === MARKDOWN_CONTENT_TYPES.ARTICLE &&
(i18n.language === LANGUAGES.DT || post.lang === i18n.language)
)
.slice(0, 3),
imageFormatEnum: ImageFormatEnum.HIGHLIGHTED_ARTICLE_POST_CARD_COVER,
imageFormat: IMAGE_FORMATS.HIGHLIGHTED_ARTICLE_POST_CARD_COVER,
});
const lastTutorialsForCardList = usePostsForCardList({
posts: postListPageData.posts
.filter(
(post) =>
post.contentType === ContentTypeEnum.TUTORIAL &&
(i18n.language === LanguageEnum.DT || post.lang === i18n.language)
post.contentType === MARKDOWN_CONTENT_TYPES.TUTORIAL &&
(i18n.language === LANGUAGES.DT || post.lang === i18n.language)
)
.slice(0, 2),
imageFormatEnum: ImageFormatEnum.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER,
imageFormat: IMAGE_FORMATS.HIGHLIGHTED_TUTORIAL_POST_CARD_COVER,
});

useTitle(t('pages.home.seo.title'));
Expand Down Expand Up @@ -73,7 +73,7 @@ export const useHomePageContainer = (): HomePageProps => {
posts: lastTutorialsForCardList,
linkSeeMore: {
label: t('pages.home.last-tutorials-block.link-see-more'),
href: generatePath(PATHS.CATEGORY, { categoryName: ContentTypeEnum.TUTORIAL, lang: i18n.language }),
href: generatePath(PATHS.CATEGORY, { categoryName: MARKDOWN_CONTENT_TYPES.TUTORIAL, lang: i18n.language }),
},
}
: undefined,
Expand Down
@@ -1,6 +1,6 @@
import { PostCardListProps } from '@eleven-labs/design-system';

import { ImageFormatEnum, NUMBER_OF_ITEMS_PER_PAGE } from '@/constants';
import { IMAGE_FORMATS, NUMBER_OF_ITEMS_PER_PAGE } from '@/constants';
import { usePostsForCardList } from '@/hooks/usePostsForCardList';

import { PostCardListContainerProps } from './PostCardListContainer';
Expand All @@ -20,7 +20,7 @@ export const usePostCardListContainer = ({
isLoading,
numberOfItems: NUMBER_OF_ITEMS_PER_PAGE,
posts,
imageFormatEnum: ImageFormatEnum.POST_CARD_COVER,
imageFormat: IMAGE_FORMATS.POST_CARD_COVER,
});

return {
Expand Down

0 comments on commit 091cc3c

Please sign in to comment.