Skip to content

Commit

Permalink
redesigned article details, fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Bender101 committed Jan 11, 2024
1 parent ca2e238 commit 7b10f72
Show file tree
Hide file tree
Showing 17 changed files with 277 additions and 160 deletions.
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,6 +1,6 @@
import { classNames } from "@/shared/lib/classNames/classNames";
import { memo } from "react";
import { Code } from "@/shared/ui/deprecated/Code";
import { Code } from "@/shared/ui/redesigned/Code";
import cls from "./ArticleCodeBlockComponent.module.scss";
import { ArticleCodeBlock } from "../../model/types/article";

Expand Down
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;
}
168 changes: 90 additions & 78 deletions src/entities/Article/ui/ArticleDetails/ArticleDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
import { classNames } from "@/shared/lib/classNames/classNames";
import { useTranslation } from "react-i18next";
import { memo, useCallback, useEffect } from "react";
import { memo, useEffect } from "react";
import { useSelector } from "react-redux";
import {
DynamicModuleLoader,
ReducersList,
} from "@/shared/lib/components/DynamicModuleLoader/DynamicModuleLoader";
import { classNames } from "@/shared/lib/classNames/classNames";
import { useAppDispatch } from "@/shared/lib/hooks/useAppDispatch/useAppDispatch";
import { Text, TextAlign, TextSize } from "@/shared/ui/deprecated/Text";
import { Skeleton } from "@/shared/ui/deprecated/Skeleton";
import {
Text as TextDeprecated,
TextAlign,
TextSize,
} from "@/shared/ui/deprecated/Text";
import { Text } from "@/shared/ui/redesigned/Text";
import {
Skeleton as SkeletonDeprecated,
Skeleton,
} from "@/shared/ui/deprecated/Skeleton";
import { Avatar } from "@/shared/ui/deprecated/Avatar";
import EyeIcon from "@/shared/assets/icons/eye-20-20.svg";
import CalendarIcon from "@/shared/assets/icons/calendar-20-20.svg";
import { Icon } from "@/shared/ui/deprecated/Icon";
import { HStack, VStack } from "@/shared/ui/redesigned/Stack";
import { fetchArticleById } from "../../model/services/fetchArticleById/fetchArticleById";
import { articleDetailsReducer } from "../../model/slice/articleDetailsSlice";
import cls from "./ArticleDetails.module.scss";
import {
getArticleDetailsData,
getArticleDetailsError,
getArticleDetailsIsLoading,
} from "../../model/selectors/articleDetails";
import { ArticleBlock } from "../../model/types/article";
import {
DynamicModuleLoader,
ReducersList,
} from "@/shared/lib/components/DynamicModuleLoader/DynamicModuleLoader";
import { ArticleCodeBlockComponent } from "../ArticleCodeBlockComponent/ArticleCodeBlockComponent";
import { ArticleTextBlockComponent } from "../ArticleTextBlockComponent/ArticleTextBlockComponent";
import { ArticleImageBlockComponent } from "../ArticleImageBlockComponent/ArticleImageBlockComponent";
import { HStack, VStack } from "@/shared/ui/redesigned/Stack";
import { articleDetailsReducer } from "../../model/slice/articleDetailsSlice";
import { ArticleBlockType } from "../../model/consts/consts";
import { renderArticleBlock } from "./renderBlock";
import { ToggleFeatures } from "@/shared/lib/features";
import { AppImage } from "@/shared/ui/redesigned/AppImage";

interface ArticleDetailsProps {
className?: string;
Expand All @@ -37,48 +43,61 @@ const reducers: ReducersList = {
articleDetails: articleDetailsReducer,
};

const Deprecated = () => {
const article = useSelector(getArticleDetailsData);
return (
<>
<HStack justify="center" max className={cls.avatarWrapper}>
<Avatar size={200} src={article?.img} className={cls.avatar} />
</HStack>
<VStack gap="4" max data-testid="ArticleDetails.Info">
<TextDeprecated
className={cls.title}
title={article?.title}
text={article?.subtitle}
size={TextSize.L}
/>
<HStack gap="8" className={cls.articleInfo}>
<Icon className={cls.icon} Svg={EyeIcon} />
<TextDeprecated text={String(article?.views)} />
</HStack>
<HStack gap="8" className={cls.articleInfo}>
<Icon className={cls.icon} Svg={CalendarIcon} />
<TextDeprecated text={article?.createdAt} />
</HStack>
</VStack>
{article?.blocks.map(renderArticleBlock)}
</>
);
};

const Redesigned = () => {
const article = useSelector(getArticleDetailsData);

return (
<>
<Text title={article?.title} size="l" bold />
<Text title={article?.subtitle} />
<AppImage
fallback={<Skeleton width="100%" height={420} border="16px" />}
src={article?.img}
className={cls.img}
/>
{article?.blocks.map(renderArticleBlock)}
</>
);
};

export const ArticleDetails = memo((props: ArticleDetailsProps) => {
const { className, id } = props;
const { t } = useTranslation("article-details");
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isLoading = useSelector(getArticleDetailsIsLoading);
const article = useSelector(getArticleDetailsData);
const error = useSelector(getArticleDetailsError);

const renderBlock = useCallback((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;
}
}, []);

useEffect(() => {
if (__PROJECT__ !== "storybook") {
dispatch(fetchArticleById(id || ""));
!!id && dispatch(fetchArticleById(id));
}
}, [dispatch, id]);

Expand All @@ -87,47 +106,40 @@ export const ArticleDetails = memo((props: ArticleDetailsProps) => {
if (isLoading) {
content = (
<>
<Skeleton
<SkeletonDeprecated
className={cls.avatar}
width={200}
height={200}
border="50%"
/>
<Skeleton className={cls.title} width={300} height={32} />
<Skeleton className={cls.skeleton} width={600} height={24} />
<Skeleton className={cls.skeleton} width="100%" height={200} />
<Skeleton className={cls.skeleton} width="100%" height={200} />
<SkeletonDeprecated className={cls.title} width={300} height={32} />
<SkeletonDeprecated className={cls.skeleton} width={600} height={24} />
<SkeletonDeprecated
className={cls.skeleton}
width="100%"
height={200}
/>
<SkeletonDeprecated
className={cls.skeleton}
width="100%"
height={200}
/>
</>
);
} else if (error) {
content = (
<Text align={TextAlign.CENTER} title={t("article_loading_error")} />
<TextDeprecated
align={TextAlign.CENTER}
title={t("article_loading_error")}
/>
);
} else {
content = (
<>
<HStack justify="center" max className={cls.avatarWrapper}>
<Avatar size={200} src={article?.img} className={cls.avatar} />
</HStack>
<VStack gap="4" max data-testid="ArticleDetails.Info">
<Text
className={cls.title}
title={article?.title}
text={article?.subtitle}
size={TextSize.L}
/>
<HStack gap="8" className={cls.articleInfo}>
<Icon className={cls.icon} Svg={EyeIcon} />
<Text text={String(article?.views)} />
</HStack>
<HStack gap="8" className={cls.articleInfo}>
<Icon className={cls.icon} Svg={CalendarIcon} />
<Text text={article?.createdAt} />
</HStack>
</VStack>

{article?.blocks.map(renderBlock)}
</>
<ToggleFeatures
feature="isAppRedesigned"
on={<Redesigned />}
off={<Deprecated />}
/>
);
}

Expand Down
38 changes: 38 additions & 0 deletions src/entities/Article/ui/ArticleDetails/renderBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ArticleBlock } from "../../model/types/article";
import { ArticleBlockType } from "../../model/consts/consts";
import { ArticleCodeBlockComponent } from "../ArticleCodeBlockComponent/ArticleCodeBlockComponent";
import cls from "./ArticleDetails.module.scss";
import { ArticleImageBlockComponent } from "../ArticleImageBlockComponent/ArticleImageBlockComponent";
import { ArticleTextBlockComponent } from "../ArticleTextBlockComponent/ArticleTextBlockComponent";

export const renderArticleBlock = (block: ArticleBlock) => {
console.log(block)
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 @@ -24,6 +24,10 @@
height: 100%;
justify-content: flex-end;
}

.avatar {
margin-left: 8px;
}
}

.BIG {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,15 @@ import { AppLink } from "@/shared/ui/redesigned/AppLink";
import { getRouteArticleDetails } from "@/shared/const/router";
import { Button } from "@/shared/ui/redesigned/Button";
import { HStack, VStack } from "@/shared/ui/redesigned/Stack";
import {
ArticleBlockType,
ArticleView,
} from "../../../model/consts/consts";
import { ArticleBlockType, ArticleView } from "../../../model/consts/consts";

export const ArticleListItemRedesigned = memo((props: ArticleListItemProps) => {
const { className, article, view, target } = props;
const { t } = useTranslation();

const userInfo = (
<>
<Avatar size={32} src={article.user.avatar} />
<Avatar size={32} src={article.user.avatar} className={cls.avatar} />
<Text bold text={article.user.username} />
</>
);
Expand Down Expand Up @@ -86,9 +83,9 @@ export const ArticleListItemRedesigned = memo((props: ArticleListItemProps) => {
to={getRouteArticleDetails(article.id)}
className={classNames(cls.ArticleListItem, {}, [className, cls[view]])}
>
<Card className={cls.card} border="round">
<Card className={cls.card} border="round" padding="0">
<AppImage
fallback={<Skeleton width={200} height={200} />}
fallback={<Skeleton width="100%" height={200} />}
alt={article.title}
src={article.img}
className={cls.img}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { classNames } from "@/shared/lib/classNames/classNames";
import { memo } from "react";
import { Text } from "@/shared/ui/deprecated/Text";
import { classNames } from "@/shared/lib/classNames/classNames";
import { Text as TextDeprecated } from "@/shared/ui/deprecated/Text";
import { Text } from "@/shared/ui/redesigned/Text";
import cls from "./ArticleTextBlockComponent.module.scss";
import { ArticleTextBlock } from "../../model/types/article";
import { ToggleFeatures } from "@/shared/lib/features";

interface ArticleTextBlockComponentProps {
className?: string;
Expand All @@ -17,9 +19,32 @@ export const ArticleTextBlockComponent = memo(
<div
className={classNames(cls.ArticleTextBlockComponent, {}, [className])}
>
{block.title && <Text title={block.title} className={cls.title} />}
{block.paragraphs.map((paragraph) => (
<Text key={paragraph} text={paragraph} className={cls.paragraph} />
{block.title && (
<ToggleFeatures
feature="isAppRedesigned"
on={<Text title={block.title} className={cls.title} />}
off={<TextDeprecated title={block.title} className={cls.title} />}
/>
)}
{block.paragraphs.map((paragraph, index) => (
<ToggleFeatures
key={index}
feature="isAppRedesigned"
on={
<Text
key={paragraph}
text={paragraph}
className={cls.paragraph}
/>
}
off={
<TextDeprecated
key={paragraph}
text={paragraph}
className={cls.paragraph}
/>
}
/>
))}
</div>
);
Expand Down
3 changes: 3 additions & 0 deletions src/shared/assets/icons/copy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 7b10f72

Please sign in to comment.