Skip to content

Commit

Permalink
560-refactor: Widget principles (#636)
Browse files Browse the repository at this point in the history
* refactor: 560 - principles scss to modules

* refactor: 560 - principle card to scss modules

* refactor: 560 - move principles to separate folder

* refactor: 560 - replace divs with semantic tags

* fix: 560 - test issue

* refactor: 560 - replace interface with type

* refactor: 560 - move data to dev-data folder

* refactor: 560 - remove unnecessary z-indexes

* refactor: 560 - remove file extensions from import statements

* fix: 560 - test case
  • Loading branch information
Quiddlee authored Nov 13, 2024
1 parent 86e1188 commit 2642a10
Show file tree
Hide file tree
Showing 14 changed files with 104 additions and 131 deletions.
1 change: 1 addition & 0 deletions dev-data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export { mentorshipCourses, mentorshipCoursesDefault } from './mentorship.data';
export { nodejs } from './nodejs.data';
export { picturesSocialMediaLinks } from './pictures.data';
export { preSchoolEn, preSchoolRu } from './preSchool.data';
export { principleCards } from './principle-cards.data';
export { reactEn } from './react-en.data';
export { reactRu } from './react-ru.data';
export { requirementsData } from './requirements.data';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { PrincipleCardProps } from './ui/principle-card/principle-card';
import { OpenSourcePhilosophyIcon, OpenToEveryoneIcon, TeachItForwardIcon } from '@/shared/icons';
import Image from 'next/image';
import openSourcePhilosophyIcon from '@/shared/assets/svg/openSourcePhilosophyIcon.svg';
import openToEveryoneIcon from '@/shared/assets/svg/openToEveryoneIcon.svg';
import teachItForwardIcon from '@/shared/assets/svg/teachItForwardIcon.svg';
import { PrincipleCard } from '@/widgets/principles';

export const cards: PrincipleCardProps[] = [
export const principleCards: PrincipleCard[] = [
{
title: 'Open to everyone',
description:
'Free courses, no obligations, and no contracts. No age limit. Only students’ time and dedication are required. Students can repeatedly attend courses.',
icon: <OpenToEveryoneIcon />,
icon: <Image src={openToEveryoneIcon} alt="" aria-hidden="true" />,
},
{
title: 'Open source philosophy',
description:
'Our Learning Management System platform and educational materials are publicly available on GitHub and YouTube.',
icon: <OpenSourcePhilosophyIcon />,
icon: <Image src={openSourcePhilosophyIcon} alt="" aria-hidden="true" />,
},
{
title: '"Teach it forward"',
description:
'Students study at school for free, but we request that they return as mentors to pass on their knowledge to the next generation of students.',
icon: <TeachItForwardIcon />,
icon: <Image src={teachItForwardIcon} alt="" aria-hidden="true" />,
},
];
3 changes: 0 additions & 3 deletions src/shared/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ export { JavascriptIcon } from './javascript-icon';
export { JetBrainsLogo } from './jetbrains';
export { LinkedInIcon } from './linkedIn';
export { NodeJsIcon } from './nodejs-icon';
export { OpenSourcePhilosophyIcon } from './open-source-philosophy-icon';
export { OpenToEveryoneIcon } from './open-to-everyone-icon';
export { ReactIcon } from './react-icon';
export { TeachItForwardIcon } from './teach-It-forward-icon';
export { TelegramIcon } from './telegram';
export { TextLinkIcon } from './text-link-icon';
export { YouTubeIcon } from './youtube';
6 changes: 0 additions & 6 deletions src/shared/icons/open-source-philosophy-icon.tsx

This file was deleted.

6 changes: 0 additions & 6 deletions src/shared/icons/open-to-everyone-icon.tsx

This file was deleted.

6 changes: 0 additions & 6 deletions src/shared/icons/teach-It-forward-icon.tsx

This file was deleted.

3 changes: 2 additions & 1 deletion src/widgets/principles/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Principles } from './ui/principle-card/principles';
export type { PrincipleCard } from './types';
export { Principles } from './ui/principles/principles';
7 changes: 7 additions & 0 deletions src/widgets/principles/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ReactNode } from 'react';

export type PrincipleCard = {
title: string;
description: string;
icon: ReactNode;
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
.principle-card {
@extend %transition-all;

cursor: default;

position: relative;

overflow: hidden;
display: flex;
flex-flow: column nowrap;
place-content: center flex-start;
align-items: flex-start;
display: grid;
grid-template-columns: max-content 1fr;
column-gap: 16px;

width: 100%;
padding: 24px;
Expand All @@ -20,7 +17,22 @@
border: 1px solid rgb(255 219 32 / 8%);
border-radius: 12px;

& .card-header {
&::after {
content: '';

position: absolute;
right: -160px;
bottom: -150px;

width: 310px;
height: 300px;

background-color: rgb(255 219 32 / 20%);
filter: blur(32px);
border-radius: 100%;
}

.card-header {
display: flex;
gap: 16px;
align-items: center;
Expand All @@ -33,43 +45,43 @@
}
}

& .icon-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.card-description {
z-index: 1;

grid-column: span 2;

& .card-description {
font-size: 18px;
font-weight: $font-weight-regular;
line-height: 1.4;
text-align: left;
letter-spacing: 0;
}

span > img {
width: 44px;
height: 44px;
}
.icon {
display: flex;
justify-content: center;

& .accent {
position: absolute;
z-index: 1;
img {
position: relative;
width: 44px;
height: 44px;
}

display: block;
flex-shrink: 0;
align-self: flex-start;
&::before {
content: '';

width: 20px;
height: 19px;
position: absolute;

background-color: rgba($color-yellow, $opacity-80);
filter: blur(8px);
border-radius: 100%;
width: 20px;
height: 20px;

background-color: rgba($color-yellow, $opacity-80);
filter: blur(8px);
border-radius: 100%;
}
}

& .card-title {
.card-title {
align-self: flex-start;

max-width: 265px;
Expand All @@ -96,26 +108,9 @@
width: 100%;
padding: 32px 24px;

& .card-description {
.card-description {
font-size: 16px;
line-height: 24px;
}
}
}

.accent-corner {
position: absolute;
z-index: 1;
right: -160px;
bottom: -150px;

display: block;
flex-shrink: 0;

width: 310px;
height: 300px;

background-color: rgb(255 219 32 / 20%);
filter: blur(32px);
border-radius: 100%;
}
31 changes: 12 additions & 19 deletions src/widgets/principles/ui/principle-card/principle-card.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { ReactNode } from 'react';
import classnames from 'classnames/bind';
import { Paragraph } from '@/shared/ui/paragraph';
import { WidgetTitle } from '@/shared/ui/widget-title';
import type { PrincipleCard as TPrincipleCard } from '@/widgets/principles';

import './principle-card.scss';
import styles from './principle-card.module.scss';

export interface PrincipleCardProps {
title: string;
description: string;
icon: ReactNode;
}
const cx = classnames.bind(styles);

export const PrincipleCard = ({ title, description, icon }: PrincipleCardProps) => (
<div className="principle-card">
<div className="card-header">
<div className="icon-wrapper">
<div className="accent" />
<span>{icon}</span>
</div>
<div className="card-title">{title}</div>
</div>
<div className="card-description">{description}</div>
<div className="accent-corner" />
</div>
export const PrincipleCard = ({ title, description, icon }: TPrincipleCard) => (
<article className={cx('principle-card')} data-testid="principle-card">
<span className={cx('icon')}>{icon}</span>
<WidgetTitle className={cx('card-title')}>{title}</WidgetTitle>
<Paragraph className={cx('card-description')}>{description}</Paragraph>
</article>
);
18 changes: 0 additions & 18 deletions src/widgets/principles/ui/principle-card/principles.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
.principles {
&.content {
padding: 20px 120px 40px;

@include media-laptop {
padding: 20px 40px 40px;
}

@include media-tablet {
padding: 20px 16px 40px;
}
}

& .cards {
.cards {
gap: 32px;
align-items: stretch;
margin-top: 24px;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it } from 'vitest';
import { cards } from './constants';
import { Principles } from '@/widgets/principles';
import { principleCards } from 'data';

import { Principles } from './ui/principle-card/principles';
const principleItemsNum = 3;

describe('Principles', () => {
beforeEach(() => {
Expand All @@ -18,7 +19,7 @@ describe('Principles', () => {
});

it('renders PrincipleCards correctly', () => {
cards.forEach(({ title, description }) => {
principleCards.forEach(({ title, description }) => {
const titleElement = screen.getByText(title);
const descriptionElement = screen.getByText(description);

Expand All @@ -28,8 +29,8 @@ describe('Principles', () => {
});

it('renders the correct number of PrincipleCards', () => {
const principleCards = document.getElementsByClassName('principle-card');
const principleCards = screen.getAllByTestId('principle-card');

expect(principleCards).toHaveLength(cards.length);
expect(principleCards).toHaveLength(principleItemsNum);
});
});
23 changes: 23 additions & 0 deletions src/widgets/principles/ui/principles/principles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import classnames from 'classnames/bind';
import { WidgetTitle } from '@/shared/ui/widget-title';
import { PrincipleCard } from '@/widgets/principles/ui/principle-card/principle-card.tsx';
import { principleCards } from 'data';

import styles from './principles.module.scss';

const cx = classnames.bind(styles);

export const Principles = () => (
<section className={cx('principles', 'container')}>
<div className={cx('principles', 'content')}>
<WidgetTitle size="large" mods="lines">
RS School Principles are an ability to complete our mission
</WidgetTitle>
<div className={cx('column-3', 'cards')}>
{principleCards.map(({ title, description, icon }) => (
<PrincipleCard key={title} description={description} icon={icon} title={title} />
))}
</div>
</div>
</section>
);

0 comments on commit 2642a10

Please sign in to comment.