Skip to content

Commit

Permalink
Merge pull request #62 from sulianova/SofiaUlianova/add-catalogue-page
Browse files Browse the repository at this point in the history
Sofia ulianova/add catalogue page
  • Loading branch information
sulianova authored Apr 5, 2024
2 parents ba54270 + d759978 commit eddbbd3
Show file tree
Hide file tree
Showing 19 changed files with 387 additions and 44 deletions.
7 changes: 7 additions & 0 deletions src/assets/translations/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@
}
}
},
"catalogue": {
"title": "Программы обучения",
"description": "Познакомимся с иллюстрацией, погрузимся в конкретные темы, потренируемся в цифровом и обычном рисовании",
"card": {
"info": "{{startDate}} – {{endDate}} | {{duration}}"
}
},
"day": {
"p_one": "день",
"p_few": "дня",
Expand Down
7 changes: 0 additions & 7 deletions src/pages/Catalogue.tsx

This file was deleted.

38 changes: 38 additions & 0 deletions src/pages/Catalogue/Catalogue.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@import 'styles/index';

.headerWrapper {
position: relative;
display: block;

padding-bottom: set-calc(24);

@include set-media(md) {
padding-bottom: set-calc(16);
}
}

.headerTitle {
font-family: $font-family-serif;
@include s-text-56;
}

.descriptionWrapper {
position: relative;

display: grid;
grid-column-gap: set-calc(1.5 * $s-gap);
grid-template-columns: repeat(8, minmax(0, 1fr));
padding-bottom: set-calc(54);

@include set-media(md) {
display: flex;
flex-direction: column;
padding-bottom: set-calc(32);
}
}

.description {
position: relative;

grid-column: span 4;
}
24 changes: 24 additions & 0 deletions src/pages/Catalogue/Catalogue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Page, { EFooter } from 'ui/Page/Page';

import List from './List/List';

import classes from './Catalogue.module.scss';
import { i18n } from 'shared';

export default Catalogue;

function Catalogue() {
return (
<Page header footer={EFooter.Big} wrapper='Catalogue'>
<div className={classes.headerWrapper}>
<h1 className={classes.headerTitle }>{i18n.t('catalogue.title')}</h1>
</div>
<div className={classes.descriptionWrapper }>
<div className={classes.description + ' s-text-24'}>{i18n.t('catalogue.description')}</div>
</div>
<List></List>
</Page>
);
}


135 changes: 135 additions & 0 deletions src/pages/Catalogue/List/Card/Card.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
@import 'styles/index';

.__ {
grid-column: span 4;
margin-bottom: set-calc(24);

will-change: transform;
}


.preview {
position: relative;

width: 100%;
margin-bottom: set-calc(16);
overflow: hidden;

background-color: $beige;
border-radius: set-calc(20);

box-shadow: 0 set-calc(4) set-calc(8) rgb(0 0 0 / 10%);
transition: opacity 0.35s ease;

aspect-ratio: 1.1 / 1;

@include set-media(md) {
margin-bottom: set-calc(16);
}

img {
position: absolute;
inset: 0;

display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

&:hover {
transform: translateY(set-calc(-3));
}
}

.previewLink {
position: absolute;
inset: 0;

z-index: 1;
}

.content {
display: flex;
flex-direction: column;
box-sizing: border-box;
padding-right: set-calc(24);
}

.title {
font-family: $font-family-serif;
margin-bottom: set-calc(16);

@include set-media(md) {
margin-bottom: set-calc(16);
}

&:hover {
color: $orange;
}
}

.info {
margin-bottom: set-calc(16);

@include set-media(md) {
margin-bottom: set-calc(8);
}
}


.description {
margin-bottom: set-calc(48);
padding-right: set-calc(48);
overflow-y: hidden;

@include set-media(md) {
margin-bottom: set-calc(24);
}
}

.tags {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
margin-bottom: set-calc(24);
padding-right: set-calc(64);

@include set-media(md) {
padding-right: 0;
}
}

.tag {
background-image: linear-gradient(to bottom, $grey 0, $grey 100%);
background-position: 0 90%;
background-repeat: repeat-x;
background-size: set-calc(1) set-calc(1);
color: $grey-inactive;
width: fit-content;

margin-right: set-calc(6);
cursor: pointer;

&:hover {
background-image: linear-gradient(to bottom, $grey-inactive 0, $grey-inactive 100%);
background-position: 0 90%;
background-repeat: repeat-x;
background-size: set-calc(1) set-calc(1);

color: $grey-inactive;
}
}

.hashTag {
display: inline-block;
vertical-align: top;
line-height: set-calc(22);
margin-right: set-calc(6);

color: $grey-inactive;

@include set-media(md) {
line-height: set-calc(19);
}
}
49 changes: 49 additions & 0 deletions src/pages/Catalogue/List/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { ICourseData } from 'services/course.service';
import { i18n } from 'shared';
import { URLSections } from 'types';
import { formatDate } from 'utils';

import Img from 'ui/Img/Img';
import Link from 'ui/Link/Link';

import classes from './Card.module.scss';

interface IProps {
course: ICourseData
}

export default function Card({ course }: Readonly<IProps>) {
return (
<div className={classes.__}>
<div className={classes.preview}>
<Link
className={classes.previewLink}
to={URLSections.Course.to({ courseId: course.id })}
/>
<Img src={course.cardImage?.imageSrc ?? ''} alt={course.cardImage?.imageAlt ?? ''}/>
</div>
<div className={classes.content}>
<Link
className={classes.title + ' s-text-36'}
to={URLSections.Course.to({ courseId: course.id })}
>
{course.title}
</Link>
<div className={classes.info}>
<div className={classes.infoDate + ' s-text-21'}>
{i18n.t('catalogue.card.info', {
startDate: formatDate(course.startDate, { timeZone: 'Europe/Moscow' }),
endDate: formatDate(course.endDate, { timeZone: 'Europe/Moscow' }),
duration: i18n.t(`duration.${course.duration.unit}`, { count: course.duration.value }),
})}
</div>
</div>
<div className={classes.description + ' s-text-18'}>{course.introDescription}</div>
<div className={classes.tags}>
<span className={classes.hashTag}>#</span>
{course.tags?.map(tag => (<span key={tag} className={classes.tag + ' s-text-16'}>{tag}</span>))}
</div>
</div>
</div>
);
}
21 changes: 21 additions & 0 deletions src/pages/Catalogue/List/List.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@import 'styles/index';

.wrapper {
@include is-grid-12;
grid-gap: set-calc($s-gap * 2);
margin-top: set-calc(24);
}

.wrapperShowMore {
grid-column: span 12;
margin: 0 0 set-calc(140);
padding: set-calc(8) 0 0;

border-top: set-calc(calc($s-gap / 2)) solid $black-new;

&Btn {
grid-column: 3 / 4;
margin-right: 0;
margin-left: auto;
}
}
35 changes: 35 additions & 0 deletions src/pages/Catalogue/List/List.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import classNames from 'classnames/bind';
import { useEffect, useState } from 'react';
import { ICourseData, courseService } from 'services/course.service';

import Card from './Card/Card';

import classes from './List.module.scss';

export default function List() {
const [courses, setCourses] = useState<ICourseData[] | null>(null);
useEffect(() => {
let cancelled = false;
const s = courseService.getCourseBS()
.subscribe(o => {
if (!o || o instanceof Error || cancelled) {
return;
}
setCourses(o.courses.filter(course => !['illustration', 'how-to-draw-free'].includes(course.id)));
});
return () => {
s.unsubscribe();
cancelled = true;
};
}, []);

if (!courses) {
return null;
}

return (
<div className={classes.wrapper}>
{courses.map(course => <Card key={course.id} course={course}/>)}
</div>
);
}
2 changes: 2 additions & 0 deletions src/pages/My/Profile/CourseCard.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
box-shadow: 0 set-calc(4) set-calc(8) rgb(0 0 0 / 10%);
border-radius: set-calc(20);

aspect-ratio: 1.1 / 1;

@include set-media(md) {
width: 100%;
}
Expand Down
16 changes: 9 additions & 7 deletions src/pages/My/Profile/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,22 @@ function Profile(props: IProps) {

const userId = props.user.id;
useEffect(() => {
let subscription: Subscription;
courseService
let cancelled = false;
const s = courseService
.getCourseBS({ filter: { userId }})
.then(bs => {
subscription = bs.subscribe(action => {
.subscribe(action => {
if (action && !(action instanceof Error)) {
setCourses(action.courses);
setCourseState({ type: 'idle' });
} else if (action instanceof Error) {
setCourses(undefined);
setCourseState({ type: 'error', error: action, errorType: action.ErrorType });
}
})
});
return () => {
s.unsubscribe();
cancelled = true;
};
}, [userId]);

const fallback = useFallback({ courseState });
Expand Down Expand Up @@ -101,8 +103,8 @@ function renderCourses(courses: ICourseData[]) {
</div>
<div className={classesCourseCard.cover}>
<Img
src={course.introImageSrc}
alt={course.introImageAlt}
src={course.cardImage?.imageSrc ?? ''}
alt={course.cardImage?.imageAlt ?? ''}
/>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { IRootState, IUserState, URLSections } from 'types';
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';

// import FreeZone from 'pages/FreeZone';
import Catalogue from 'pages/Catalogue';
import Catalogue from 'pages/Catalogue/Catalogue';
import Course from 'pages/Course/Landing/Course';
import Lesson from 'pages/Course/Lesson/Lesson';
import Lessons from 'pages/Course/Lessons/Lessons';
Expand Down Expand Up @@ -38,7 +38,7 @@ function MyRouter({ userState }: IProps) {
<AuthContext.Provider value={userState}>
<BrowserRouter>
<Routes>
<Route index path={URLSections.FreeZone.index} element={<Navigate to={URLSections.Course.to({ courseId: 'how-to-draw' })} />} />
<Route index path={URLSections.FreeZone.index} element={<Navigate to={URLSections.Catalogue.index} />} />
<Route path={URLSections.Catalogue.index} element={<Catalogue />} />
<Route path={URLSections.Course.index} element={<Course />} />
<Route path={URLSections.Course.Lessons.index} element={<Lessons />} />
Expand Down
Loading

0 comments on commit eddbbd3

Please sign in to comment.