LendingTelecom/landing/src/components/ScreenSecond/index.jsx

238 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/components/ScreenSecond/index.tsx
import styled from "styled-components";
import fallbackLogo from "imgs/logo.svg";
import arrowTop from "imgs/arrow_top.svg";
import {
s_f_Text18_400,
s_Text18_400 as Text18_400,
s_Text24_700 as Text24_700,
s_Text40_700 as Text40_700,
s_Text14_400 as Text14_400,
} from "../Typography";
import { useSingleton } from "cms/factory";
import { AsyncReveal } from "../AsyncReveal";
/* ===================== TYPES & GQL ===================== */
type Row = {
id: string;
value: string;
label: string;
trend: "none" | "up" | "down";
order: number;
};
type Section = {
id: string;
title?: string | null;
description?: string | null;
logo?: { url?: string | null } | null;
footnote?: string | null;
rows: Row[];
};
const SELECTION = `
id
title
description
logo { url }
footnote
rows(orderBy: { order: asc }) {
id
value
label
trend
order
}
`;
/* ===================== UTILS ===================== */
function chunkInto<T>(arr: T[], size: number): T[][] {
const out: T[][] = [];
for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
return out;
}
/* ===================== STYLES ===================== */
const ScreenSecondBlock = styled.div`
width: 100%;
max-width: 1380px;
padding: 64px 10px;
margin: 0 auto;
display: flex;
justify-content: center;
@media (max-width: 768px) {
padding: 10px 10px;
}
`;
const ContentCard = styled.div`
width: 90%;
max-width: 1200px;
background: #fff;
border-radius: 16px;
padding: 64px 0;
padding-bottom: 0;
display: flex;
flex-direction: column;
@media (max-width: 768px) {
width: 100%;
padding: 10px 10px;
}
`;
const HeaderRow = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
@media (max-width: 768px) {
flex-direction: column-reverse;
align-items: flex-start;
gap: 0;
}
`;
const TitleRow = styled.div`
display: inline;
font-size: 0; /* убираем промежутки у inline-children */
`;
const TitleBlock = styled.div`
max-width: 720px;
display: flex;
flex-direction: column;
`;
const LogoBlock = styled.div`
display: flex;
align-items: center;
height: 100%;
margin-left: 30px;
img {
min-width: 185px;
height: 56px;
min-height: 56px;
}
@media (max-width: 768px) {
width: 100%;
justify-content: center;
margin-left: 0;
margin-bottom: 32px;
}
`;
const FinanceRow = styled.div`
display: flex;
justify-content: space-between;
text-align: center;
margin: 24px 0;
@media (max-width: 768px) {
flex-direction: row;
gap: 16px;
}
`;
const FinanceBlock = styled.div`
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
@media (max-width: 768px) {
width: 100%;
}
`;
const ValueRow = styled.div`
display: flex;
align-items: center;
gap: 8px;
padding-bottom: 8px;
`;
const Divider = styled.div`
width: 100%;
height: 1px;
background: #e5e7eb;
margin: 24px 0;
`;
const Arrow = styled.img`
transform: ${({ $down }) => ($down ? "rotate(180deg)" : "none")};
`;
/* ===================== COMPONENT ===================== */
function ScreenSecond() {
const { data: section, loading, error } = useSingleton(
"ScreenSecondSection",
SELECTION
);
const groups = chunkInto(section?.rows ?? [], 3);
const logoSrc = section?.logo?.url || fallbackLogo;
return (
<ScreenSecondBlock id="holding">
<ContentCard>
<AsyncReveal loading={loading} error={error} stagger={0.08} from={12}>
{/* Header */}
<HeaderRow>
<TitleBlock>
<TitleRow style={{ marginBottom: 24 }}>
{section?.title && <Text40_700>{section.title}</Text40_700>}
</TitleRow>
{section?.description && (
<s_f_Text18_400>{section.description}</s_f_Text18_400>
)}
</TitleBlock>
<LogoBlock>
<img src={logoSrc} alt="Company logo" />
</LogoBlock>
</HeaderRow>
{/* Rows in groups of 3 with Divider */}
{groups.map((group, gi) => (
<div key={`g-${gi}`}>
<FinanceRow>
{group.map((item) => (
<FinanceBlock key={item.id}>
<ValueRow>
<Text24_700>{item.value}</Text24_700>
{item.trend !== "none" && (
<Arrow
src={arrowTop}
alt={item.trend}
height={16}
$down={item.trend === "down"}
/>
)}
</ValueRow>
<Text18_400>{item.label}</Text18_400>
</FinanceBlock>
))}
</FinanceRow>
{gi < groups.length - 1 && <Divider />}
</div>
))}
{/* Footnote */}
{section?.footnote && <Text14_400>{section.footnote}</Text14_400>}
</AsyncReveal>
</ContentCard>
</ScreenSecondBlock>
);
}
export default ScreenSecond;