Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
fb31799
split timeline into Timeline and TimelineEntry components
EemeliJ Jul 15, 2026
7b876bb
Implemented collapsible timeline with sorting
EemeliJ Jul 15, 2026
af28360
Refactor: separate timeline sorting logic from timeline rendering
EemeliJ Aug 2, 2026
65561fc
Adjusted timeline dropdown positioning
EemeliJ Aug 10, 2026
4d59ff0
Updated About page layout and statistics, refined title typography, a…
EemeliJ Aug 11, 2026
8272d83
Refined the statistics card typography, spacing and layout
EemeliJ Aug 12, 2026
6174e0a
Fixed responsive statistic card layout, wrapping and breakpointbehaviour
EemeliJ Aug 13, 2026
ce6fb34
Refined spacing, layout and markers of the timeline element
EemeliJ Aug 14, 2026
96956a8
Updated the timeline sorting dropdown layout, styling and selection s…
EemeliJ Aug 16, 2026
99d9449
Made some fixes to the sorting dropdown, such as positioning and chec…
EemeliJ Aug 17, 2026
fc03b59
Fixed some positioning in the timeline, and switched pseudo arrow to …
EemeliJ Aug 18, 2026
27b91f6
Refined the sorting dropdown UI
EemeliJ Aug 19, 2026
26199fc
Added animations to the timeline entries, and button for closing
EemeliJ Aug 20, 2026
05cd885
Made some fixes to the #line behaviour across resolutions, and chevro…
EemeliJ Aug 21, 2026
689d384
Made some fixes to stat and timeline container width, hooked i18n cor…
EemeliJ Aug 22, 2026
5796e12
Added a designer block under Timeline with the name as an link to the…
EemeliJ Aug 25, 2026
856282d
Small fix to the close button in timeline entries, now it scales acco…
EemeliJ Aug 25, 2026
325374c
Removed some unused props from about.tsx
EemeliJ Sep 1, 2026
9ba2665
Added more spacing between timeline and designer containers, and set …
EemeliJ Sep 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

248 changes: 104 additions & 144 deletions frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
'use client';
import cls from './About.module.scss';
import chevronDown from '@/shared/assets/icons/chevronDown.svg';
import Image from 'next/image';
import heroTop from '@/shared/assets/images/aboutPage/hero-top.png';
import img2019 from '@/shared/assets/images/aboutPage/about2019.png';
import img2020 from '@/shared/assets/images/aboutPage/about2020.png';
import img2021 from '@/shared/assets/images/aboutPage/about2021.png';
import img2022 from '@/shared/assets/images/aboutPage/about2022.png';
import img2023 from '@/shared/assets/images/aboutPage/about2023.png';
import img2024 from '@/shared/assets/images/aboutPage/about2024.png';
import { useState } from 'react';
import cls from './About.module.scss';
import { useGetMembersCountQuery, useGetDemographicsQuery, getBehindYears } from '@/entities/About';
import { DropdownWrapper } from '@/shared/ui/DropdownWrapperV2/ui/DropdownWrapper';
import Timeline from './Timeline';
import chevronDown from '@/shared/assets/icons/chevronDown.svg';
import { useClientTranslation } from '@/shared/i18n';

export interface Props {
title: string;
description: string;
keywords: string;
storytitle: string;
project: string;
locality: string;
Expand All @@ -33,8 +28,6 @@ export interface Props {
const About = (props: Props) => {
const {
title,
description,
keywords,
storytitle,
project,
locality,
Expand All @@ -50,7 +43,14 @@ const About = (props: Props) => {
V2026,
} = props;

const { t } = useClientTranslation('about');

const designers = t('designer.names', {
returnObjects: true,
}) as { name: string; url: string }[];

const { data: projectCount = 0, isLoading: membersLoading } = useGetMembersCountQuery();

const {
data: demographics = { localities: 0, nationalities: 0 },
isLoading: demographicsLoading,
Expand All @@ -59,158 +59,118 @@ const About = (props: Props) => {
const behindCount = getBehindYears();
const isLoading = membersLoading || demographicsLoading;

const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');

return (
<main className={cls.main}>
<section
className={cls.hero}
aria-label="About hero image"
>
<Image
src={heroTop}
alt="Hero Image"
fill
priority
className={cls.heroImg}
sizes="100vw"
/>
</section>
<div className={cls.containerTop}>
<p className={`${cls.h1}`}>{title}</p>
<p className={cls.gridp}>{description}</p>
<p className={`${cls.h1}`}>{keywords}</p>
<div className={cls.headergrid}>
<div>
<p className={cls.sValues}>{isLoading ? '...' : projectCount}</p>
<p className={cls.gridp}>{project}</p>
</div>
<div>
<p className={cls.sValues}>{isLoading ? '...' : demographics.localities}</p>
<p className={cls.gridp}>{locality}</p>
</div>
<div>
<p className={cls.sValues}>
{isLoading ? '...' : demographics.nationalities}
</p>
<p className={cls.gridp}>{nationality}</p>
</div>
<div>
<p className={cls.sValues}>{behindCount}</p>
<p className={cls.gridp}>{behind}</p>
</div>
</div>
</div>
<div className={cls.containerBottom}>
<div className={cls.aboutContent}>
<p
className={`${cls.h1}`}
className={cls.h1}
id={cls.History}
>
{storytitle}
</p>
<div
className={cls.storygrid}
id={cls.line}
>
<p className={cls.yearh1}>2019</p>
<div>
<div className={cls.yearImgWrap}>
<Image
src={img2019}
alt="2019 year image"
fill
className={cls.yearImg}
sizes="(max-width: 768px) 94vw, 34vw"
/>
</div>
<p className={cls.p}>{V2019}</p>
</div>

<p className={cls.yearh1}>2020</p>
<div>
<div className={cls.yearImgWrap}>
<Image
src={img2020}
alt="2020 year image"
fill
className={cls.yearImg}
sizes="(max-width: 768px) 94vw, 34vw"
/>
</div>
<p className={cls.p}>{V2020}</p>
</div>
<div className={cls.containerTop}>
<p className={cls.statsTitle}>{title}</p>

<p className={cls.yearh1}>2021</p>
<div>
<div className={cls.yearImgWrap}>
<Image
src={img2021}
alt="2021 year image"
fill
className={cls.yearImg}
sizes="(max-width: 768px) 94vw, 34vw"
/>
<div className={cls.headergrid}>
<div className={cls.statItem}>
<p className={cls.sValues}>{isLoading ? '...' : projectCount}</p>
<p className={cls.gridp}>{project}</p>
</div>
<p className={cls.p}>{V2021}</p>
</div>

<p className={cls.yearh1}>2022</p>
<div>
<div className={cls.yearImgWrap}>
<Image
src={img2022}
alt="2022 year image"
fill
className={cls.yearImg}
sizes="(max-width: 768px) 94vw, 34vw"
/>
<div className={`${cls.statItem} ${cls.statItemNarrow}`}>
<p className={cls.sValues}>
{isLoading ? '...' : demographics.localities}
</p>
<p className={cls.gridp}>{locality}</p>
</div>
<p className={cls.p}>{V2022}</p>
</div>

<p className={cls.yearh1}>2023</p>
<div>
<div className={cls.yearImgWrap}>
<Image
src={img2023}
alt="2023 year image"
fill
className={cls.yearImg}
sizes="(max-width: 768px) 94vw, 34vw"
/>
<div className={`${cls.statItem} ${cls.statItemNarrow}`}>
<p className={cls.sValues}>
{isLoading ? '...' : demographics.nationalities}
</p>
<p className={cls.gridp}>{nationality}</p>
</div>
<p className={cls.p}>{V2023}</p>
</div>

<p className={cls.yearh1}>2024</p>
<div>
<div className={cls.yearImgWrap}>
<Image
src={img2024}
alt="2024 year image"
fill
className={cls.yearImg}
sizes="(max-width: 768px) 94vw, 34vw"
/>
<div className={cls.statItem}>
<p className={cls.sValues}>{behindCount}</p>
<p className={cls.gridp}>{behind}</p>
</div>
<p className={cls.p}>{V2024}</p>
</div>
</div>

<p className={cls.yearh1}>2025</p>
<div>
<p className={cls.p}>{V2025}</p>
</div>
<div className={cls.sortContainer}>
<DropdownWrapper
dynamicTitle={t('timeline.sort')}
showArrow
autoClose
className={cls.timelineSortDropdown}
headerClassName={cls.timelineSortHeader}
contentClassName={cls.timelineSortContent}
contentItemClassName={cls.timelineSortItem}
activeItemClassName={cls.timelineSortItemActive}
chevronWrapperClassName={cls.timelineSortChevronWrapper}
elements={[
{
elementText: t('timeline.newest'),
active: sortOrder === 'desc',
onClickCallback: () => setSortOrder('desc'),
},
{
elementText: t('timeline.oldest'),
active: sortOrder === 'asc',
onClickCallback: () => setSortOrder('asc'),
},
]}
/>
</div>

<p className={cls.yearh1}>2026</p>
<div>
<p className={cls.p}>{V2026}</p>
<div className={cls.containerBottom}>
<div
className={`${cls.storygrid} ${
sortOrder === 'desc' ? cls.timelineNewest : cls.timelineOldest
}`}
id={cls.line}
>
<Image
src={chevronDown}
alt=""
aria-hidden="true"
className={cls.timelineChevron}
/>

<Timeline
sortOrder={sortOrder}
V2019={V2019}
V2020={V2020}
V2021={V2021}
V2022={V2022}
V2023={V2023}
V2024={V2024}
V2025={V2025}
V2026={V2026}
/>
</div>
</div>

<Image
loading="eager"
alt={'Chevron'}
src={chevronDown}
className={cls.chevronImage}
width={50}
/>
<div className={cls.designerContainer}>
<p className={cls.designerText}>
{t('designer.label')}{' '}
{designers.map((designer, index) => (
<span key={designer.name}>
{index > 0 && ', '}
<a
href={designer.url}
target="_blank"
rel="noopener noreferrer"
>
{designer.name}
</a>
</span>
))}
</p>
</div>
</div>
</main>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { StaticImageData } from 'next/image';
import img2019 from '@/shared/assets/images/aboutPage/about2019.png';
import img2020 from '@/shared/assets/images/aboutPage/about2020.png';
import img2021 from '@/shared/assets/images/aboutPage/about2021.png';
import img2022 from '@/shared/assets/images/aboutPage/about2022.png';
import img2023 from '@/shared/assets/images/aboutPage/about2023.png';
import img2024 from '@/shared/assets/images/aboutPage/about2024.png';
import TimelineEntry from './TimelineEntry';

interface Props {
sortOrder: 'asc' | 'desc';
V2019: string;
V2020: string;
V2021: string;
V2022: string;
V2023: string;
V2024: string;
V2025: string;
V2026: string;
}

interface TimelineItem {
year: number;
text: string;
image: StaticImageData | null;
}

const Timeline = ({ sortOrder, V2019, V2020, V2021, V2022, V2023, V2024, V2025, V2026 }: Props) => {
const timeline: TimelineItem[] = [
{ year: 2019, image: img2019, text: V2019 },
{ year: 2020, image: img2020, text: V2020 },
{ year: 2021, image: img2021, text: V2021 },
{ year: 2022, image: img2022, text: V2022 },
{ year: 2023, image: img2023, text: V2023 },
{ year: 2024, image: img2024, text: V2024 },
{ year: 2025, image: null, text: V2025 },
{ year: 2026, image: null, text: V2026 },
];

const sortedTimeline = [...timeline].sort((a, b) =>
sortOrder === 'desc' ? b.year - a.year : a.year - b.year,
);

return (
<>
{sortedTimeline.map((item, index) => (
<TimelineEntry
key={item.year}
year={item.year}
text={item.text}
image={item.image}
sortOrder={sortOrder}
isFirst={index === 0}
isLast={index === sortedTimeline.length - 1}
/>
))}
</>
);
};

export default Timeline;
Loading