Skip to content

Commit

Permalink
feat: redesign article details content
Browse files Browse the repository at this point in the history
  • Loading branch information
TomatoVan committed Apr 25, 2024
1 parent 28edc59 commit 6c86a8c
Show file tree
Hide file tree
Showing 19 changed files with 1,162 additions and 1,081 deletions.
1,760 changes: 905 additions & 855 deletions json-server/db.json

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/app/styles/reset.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ select {
a {
text-decoration: none;
}

h1,
h2,
h3,
h4,
h5,
h6, {
font-weight: 300;
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { useTranslation } from 'react-i18next';
import { memo } from 'react';
import { classNames } from '@/shared/lib/classNames/classNames';
import { ArticleCodeBlock } from '../../model/types/article';
import { Code } from '@/shared/ui/deprecated/Code';
import { Code } from '@/shared/ui/redesigned/Code';

interface ArticleCodeBlockComponentProps {
className?: string;
block?: ArticleCodeBlock;
}

export const ArticleCodeBlockComponent = memo(
({ className, block }: ArticleCodeBlockComponentProps) => {
const { t } = useTranslation();
return (
<div className={classNames('', {}, [className])}>
{block?.code && <Code text={block?.code} />}
</div>
);
},
({ className, block }: ArticleCodeBlockComponentProps) => (
<div className={classNames('', {}, [className])}>
{block?.code && <Code text={block?.code} />}
</div>
),
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@
.avatar {
margin: 0 auto;
}

.img {
width: 100%;
max-height: 420px;
}
99 changes: 18 additions & 81 deletions src/entities/Article/ui/ArticleDetails/ArticleDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import { useTranslation } from 'react-i18next';
import { memo, useCallback, useEffect } from 'react';
import { memo, useEffect } from 'react';
import { useSelector } from 'react-redux';

import { classNames } from '@/shared/lib/classNames/classNames';
import {
DynamicModuleLoader,
ReducersList,
} from '@/shared/lib/components/DynamicModuleLoared/DynamicModuleLoared';
import { useAppDispatch } from '@/shared/lib/hook/useAppDispatch/useAppDispatch';
import EyeIcon from '@/shared/assets/icons/eye-20-20.svg';
import CalendarIcon from '@/shared/assets/icons/calendar-20-20.svg';
import { ArticleBlockType } from '../../model/consts/consts';
import { ArticleImageBlockComponent } from '../ArticleImageBlockComponent/ArticleImageBlockComponent';
import { ArticleTextBlockComponent } from '../ArticleTextBlockComponent/ArticleTextBlockComponent';
import { ArticleCodeBlockComponent } from '../ArticleCodeBlockComponent/ArticleCodeBlockComponent';
import { ArticleBlock } from '../../model/types/article';
import {
getArticlesDetailsData,
getArticlesDetailsIsError,
Expand All @@ -23,16 +15,11 @@ import {
import { fetchArticleById } from '../../model/services/fetchArticleById/fetchArticleById';
import { articleDetailsReducer } from '../../model/slice/articleDetailsSlice';
import cls from './ArticleDetails.module.scss';
import { Avatar } from '@/shared/ui/deprecated/Avatar';
import { Icon } from '@/shared/ui/deprecated/Icon';
import {
TextAlign,
TextSize,
TextTheme,
Text,
} from '@/shared/ui/deprecated/Text';
import { Skeleton } from '@/shared/ui/deprecated/Skeleton';
import { HStack, VStack } from '@/shared/ui/redesigned/Stack';
import { Text } from '@/shared/ui/redesigned/Text';
import { Skeleton } from '@/shared/ui/redesigned/Skeleton';
import { VStack } from '@/shared/ui/redesigned/Stack';
import { renderArticleBlock } from './renderBlock';
import { AppImage } from '@/shared/ui/redesigned/AppImage';

interface ArticleDetailsProps {
className?: string;
Expand All @@ -51,37 +38,6 @@ export const ArticleDetails = memo(({ className, id }: ArticleDetailsProps) => {
const isLoading = useSelector(getArticlesDetailsIsLoading);
const error = useSelector(getArticlesDetailsIsError);

const renderBlock = useCallback((block: ArticleBlock) => {
switch (block.type) {
case ArticleBlockType.CODE:
return (
<ArticleCodeBlockComponent
key={block.id}
className={cls.block}
block={block}
/>
);
case ArticleBlockType.IMAGE:
return (
<ArticleImageBlockComponent
key={block.id}
className={cls.block}
block={block}
/>
);
case ArticleBlockType.TEXT:
return (
<ArticleTextBlockComponent
key={block.id}
className={cls.block}
block={block}
/>
);
default:
return null;
}
}, []);

useEffect(() => {
if (__PROJECT__ !== 'storybook') {
dispatch(fetchArticleById(id));
Expand All @@ -107,44 +63,25 @@ export const ArticleDetails = memo(({ className, id }: ArticleDetailsProps) => {
} else if (error) {
content = (
<Text
theme={TextTheme.ERROR}
variant="error"
title={t('Error with getting article data')}
text={t('Try to reload page')}
align={TextAlign.CENTER}
align="center"
/>
);
} else {
content = (
<>
<HStack
justify="center"
max
gap="8"
className={cls.avatarWrapper}
>
<Avatar
size={200}
src={article?.img}
className={cls.avatar}
/>
</HStack>
<VStack gap="4" max data-testid="ArticlesDetails.Info">
<Text
className={cls.title}
size={TextSize.L}
title={article?.title}
text={article?.subtitle}
/>
<HStack gap="8" className={cls.articleInfo}>
<Icon Svg={EyeIcon} className={cls.icon} />
<Text text={String(article?.views)} />
</HStack>
<HStack gap="8" className={cls.articleInfo}>
<Icon Svg={CalendarIcon} className={cls.icon} />
<Text text={article?.createdAt} />
</HStack>
{article?.blocks?.map(renderBlock)}
</VStack>
<Text size="l" title={article?.title} bold />
<Text size="m" title={article?.subtitle} />
<AppImage
src={article?.img}
fallback={
<Skeleton width="100%" height={420} border="16" />
}
className={cls.img}
/>
{article?.blocks?.map(renderArticleBlock)}
</>
);
}
Expand Down
37 changes: 37 additions & 0 deletions src/entities/Article/ui/ArticleDetails/renderBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ArticleBlock } from '../../model/types/article';
import { ArticleCodeBlockComponent } from '../ArticleCodeBlockComponent/ArticleCodeBlockComponent';
import cls from './ArticleDetails.module.scss';
import { ArticleImageBlockComponent } from '../ArticleImageBlockComponent/ArticleImageBlockComponent';
import { ArticleTextBlockComponent } from '../ArticleTextBlockComponent/ArticleTextBlockComponent';
import { ArticleBlockType } from '../../model/consts/consts';

export const renderArticleBlock = (block: ArticleBlock) => {
switch (block.type) {
case ArticleBlockType.CODE:
return (
<ArticleCodeBlockComponent
key={block.id}
block={block}
className={cls.block}
/>
);
case ArticleBlockType.IMAGE:
return (
<ArticleImageBlockComponent
key={block.id}
block={block}
className={cls.block}
/>
);
case ArticleBlockType.TEXT:
return (
<ArticleTextBlockComponent
key={block.id}
className={cls.block}
block={block}
/>
);
default:
return null;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { memo } from 'react';
import { classNames } from '@/shared/lib/classNames/classNames';
import { ArticleImageBlock } from '../../model/types/article';
import cls from './ArticleImageBlockComponent.module.scss';
import { TextAlign, Text } from '@/shared/ui/deprecated/Text';
import { Text } from '@/shared/ui/redesigned/Text';

interface ArticleImageBlockComponentProps {
className?: string;
Expand All @@ -21,7 +21,7 @@ export const ArticleImageBlockComponent = memo(
<Text
title={block?.title}
className={cls.title}
align={TextAlign.CENTER}
align="center"
/>
)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/entities/Article/ui/ArticleList/ArticleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
import { HTMLAttributeAnchorTarget, memo } from 'react';
import { Text } from '@/shared/ui/redesigned/Text';
import { classNames } from '@/shared/lib/classNames/classNames';
import { ArticleListItemSkeleton } from '../ArticleListItem/ArticleListItemSkeleton';
import { ArticleListItemSkeleton } from '../ArticleListItem/ArticleListItemSkeleton/ArticleListItemSkeleton';
import { ArticleListItem } from '../ArticleListItem/ArticleListItem';
import cls from './ArticleList.module.scss';
import { Article } from '../../model/types/article';
Expand Down
108 changes: 23 additions & 85 deletions src/entities/Article/ui/ArticleListItem/ArticleListItem.module.scss
Original file line number Diff line number Diff line change
@@ -1,107 +1,45 @@
.BIG {
.views {
margin-left: auto;
}

.header {
.SMALL {
.card {
width: 240px;
height: 350px;
overflow: hidden;
display: flex;
align-items: center;
}

.username {
margin-left: 8px;
}

.date {
margin-left: auto;
}

.title {
margin-top: 8px;
flex-direction: column;
gap: 8px;
}

.img {
width: 100%;
max-height: 250px;
object-fit: cover;
margin: 16px 0;
}

.footer {
display: flex;
align-items: center;
margin-top: 16px;
min-height: 140px;
max-height: 140px;
}

.textBlock {
max-height: 200px;
overflow-y: hidden;
}
}

.SMALL {
width: 230px;
transition: 0.2s;
cursor: pointer;

.date {
position: absolute;
right: 0;
top: 0;
display: none;
.info {
padding: 8px 8px 16px;
height: 100%;
}

&:hover {
opacity: 0.8;
transform: scale(1.01);

.date {
display: block;
}
.footer {
height: 100%;
justify-content: flex-end;
}

.imageWrapper {
width: 200px;
height: 200px;
position: relative;
.avatar {
margin-left: 8px;
}
}

.BIG {
.img {
width: 200px;
height: 200px;
width: 100%;
max-height: 420px;
object-fit: cover;
}

.infoWrapper {
display: flex;
align-items: center;
margin-top: 8px;
}

.types p {
width: 115px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.views {
margin-left: auto;
margin-right: 8px;
}

.title {
margin-top: 8px;
height: 26px;
overflow: hidden;
text-overflow: ellipsis;
}

.title p {
width: 200px;
white-space: nowrap;
.textBlock {
height: 72px;
overflow: hidden;
text-overflow: ellipsis;
}
}

Expand Down
Loading

0 comments on commit 6c86a8c

Please sign in to comment.