This commit is contained in:
Zakhar
2026-09-02 09:41:12 +03:00
parent 099755d516
commit 820f12d33a
24 changed files with 567 additions and 106 deletions
+16 -8
View File
@@ -1,5 +1,5 @@
import type { ReactNode } from 'react';
import styled from 'styled-components';
import styled, {css} from 'styled-components';
import { ArrowIcon } from '../Icons/ArrowIcon';
import { HeartIcon } from '../Icons/HeartIcon';
@@ -15,7 +15,6 @@ interface AccordionProps {
}
export function Accordion({
id,
title,
description,
icon,
@@ -70,6 +69,9 @@ const Header = styled.div`
background: transparent;
border: 0;
text-align: left;
${props => props.theme.media.mobile(css`
padding: 10px 20px 16px 20px;
`)};
`;
const HeaderLeft = styled.div`
@@ -78,8 +80,8 @@ const HeaderLeft = styled.div`
`;
const IconCircle = styled.div<{ $highlighted: boolean }>`
width: 44px;
height: 44px;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
@@ -89,8 +91,8 @@ const IconCircle = styled.div<{ $highlighted: boolean }>`
background: ${({ $highlighted }) => ($highlighted ? '#E6F696' : '#E7EDE7')};
img {
width: 44px;
height: 44px;
width: 40px;
height: 40px;
}
svg rect {
@@ -119,10 +121,13 @@ const ArrowWrap = styled.div<{ $open: boolean }>`
color: ${({ theme }) => theme.colors.gray};
transition: transform 0.3s ease;
transform: ${({ $open }) => ($open ? 'rotate(180deg)' : 'rotate(0deg)')};
width: 24px;
height: 24px;
margin-left:8px;
svg {
width: 16px;
height: 16px;
width: 24px;
height: 24px;
}
`;
@@ -134,4 +139,7 @@ const Content = styled.div<{ $open: boolean }>`
const ContentInner = styled.div`
padding: 0 24px 20px;
${props => props.theme.media.mobile(css`
padding: 0 20px 20px;
`)};
`;
+4
View File
@@ -323,6 +323,10 @@ const ShowMore = styled.button`
opacity: 0.8;
}
span {
color: ${({ theme }) => theme.colors.green};
}
svg {
width: 24px;
height: 24px;
+3 -1
View File
@@ -2,6 +2,7 @@ import styled from 'styled-components';
import {BagIcon} from "../Icons/BagIcon";
import {useState} from "react";
import {OrderPopup} from "./OrderPopup";
import {useAppSelector} from "../../store";
interface CartFooterProps {
@@ -11,6 +12,7 @@ interface CartFooterProps {
export function CartFooter({ isVisible, totalPrice }: CartFooterProps) {
const [showCompletePopup, setShowCompletePopup] = useState(false);
const users = useAppSelector(state => state.family.users);
return (
<Footer $visible={isVisible}>
@@ -28,7 +30,7 @@ export function CartFooter({ isVisible, totalPrice }: CartFooterProps) {
</TotalWrap>
<CheckoutButton type="button" onClick={() => setShowCompletePopup(true)}>
Оформить заказ
{users.length > 1 ? 'Нам' : 'Мне'} хватило
</CheckoutButton>
{showCompletePopup && <>
<OrderPopup setShowCompletePopup={setShowCompletePopup} />
+1
View File
@@ -151,6 +151,7 @@ const Overlay = styled.div`
justify-content: center;
align-items: center;
z-index: 9;
overflow: auto;
`;
const Dropdown = styled.div`
+8 -2
View File
@@ -13,14 +13,17 @@ export const FinishPopupContent = ({setShowCompletePopup}: any) => {
<img src="/images/broc-gifts.png" alt=""/>
<h2>Спасибо!</h2>
<p>
Вы помогли нам протестировать автокорзину. Сейчас сервис ещё разрабатывается, поэтому оформить заказ пока нельзя.
Оставьте адрес электронной почты, и после запуска мы подарим вам <strong>3 бесплатные корзины</strong>.
Вы помогли нам протестировать автокорзину. Сейчас сервис ещё разрабатывается, поэтому оформить заказ пока не получится.
</p>
<p>
Если вы оставите адрес электронной почты - после запуска мы подарим вам <strong>3 бесплатные корзины</strong>.
</p>
<TextInput placeholder={'Почта'} value={email} onChange={setEmail} />
<FinishButton onClick={() => {
if (buttonContent === 'Получить подарок') {
setButtonContent('...')
subscribeOnFinish(email).then((data) => {
// @ts-ignore
if (data && data.status === 200) {
setButtonContent('Письмо отправлено')
} else {
@@ -37,9 +40,12 @@ export const FinishPopupContent = ({setShowCompletePopup}: any) => {
const FinishPopupContentWrap = styled.div`
padding: 20px;
display: flex;
flex-direction: column;
img {
max-width: 100%;
display: flex;
}
h2 {
margin-top: 24px;
+132
View File
@@ -0,0 +1,132 @@
import styled from "styled-components";
export const FinitaLaCommedia = ({onClose, onRefresh}: any) => {
return <Overlay onClick={onClose}>
<Window onClick={event => event.stopPropagation()}>
<CloseButton type="button" aria-label="Закрыть" onClick={onClose}>
&times;
</CloseButton>
<ModalContent>
<img src="/images/broc-finita-la-commedia.png" alt="не смогли собрать корзину"/>
<div>
<h2>Больше подходящих вариантов нет</h2>
<p>
Мы больше не нашли подходящих продуктов с текущими настройками.
Можно изменить предпочтения или попробовать собрать корзину заново
</p>
</div>
<ButtonBlock>
<ActiveButton onClick={onRefresh}>Пересобрать корзину</ActiveButton>
</ButtonBlock>
</ModalContent>
</Window>
</Overlay>
}
const Overlay = styled.div`
position: fixed;
display: flex;
inset: 0;
background-color: rgba(0, 0, 0, 0.4);
justify-content: center;
align-items: center;
z-index: 4;
overflow: auto;
`;
const Window = styled.div`
background-color: #ffffff;
border-radius: 12px;
width: auto;
max-width: 535px;
padding: 20px 24px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
position: relative;
z-index: 9;
`;
const CloseButton = styled.button`
position: absolute;
top: 20px;
right: 20px;
background: none;
border: none;
width: 24px;
height: 24px;
font-weight: 300;
line-height: 12px;
color: #CEDFD0;
font-size: 24px;
cursor: pointer;
padding: 5px;
transition: 0.2s;
&:hover {
color: #ACBAAE;
}
`;
const ModalContent = styled.div`
padding: 20px;
color: #0C3B2E;
max-width: 335px;
box-sizing: content-box;
display: flex;
flex-direction: column;
gap: 24px;
> div {
display: flex;
flex-direction: column;
gap: 8px;
}
img {
max-width: 335px;
text-align: center;
margin: 0 auto;
display: block;
}
`;
const ButtonBlock = styled.div`
margin-top: 24px;
display: flex;
gap: 16px;
flex-direction: column;
`;
const Button = styled.div`
height: 54px;
border-radius: 12px;
text-align: center;
background: #fff;
color: #5EA12D;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
line-height: 16px;
cursor: pointer;
&:hover {
background-color: #F7FBF6;
}
&:active,
&:focus {
background-color: #EEF8EB;
outline: none;
}
`;
const ActiveButton = styled(Button)`
background-color: #5EA12D;
color: #fff;
font-size: 16px;
line-height: 20px;
&:hover,
&:focus {
background-color: ${({theme}) => theme.colors.greenHover};
}
&:active {
background-color: #4A8D19;
}
`;
+6 -1
View File
@@ -1,4 +1,4 @@
import styled from "styled-components";
import styled, {css} from "styled-components";
import {useState} from "react";
import {FinishPopupContent} from "./FinishPopupContent";
@@ -42,6 +42,8 @@ const Window = styled.div`
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
position: relative;
z-index: 9;
max-height: 90vh;
overflow: auto;
`;
const CloseButton = styled.button`
@@ -63,6 +65,9 @@ const CloseButton = styled.button`
&:hover {
color: #ACBAAE;
}
${({ theme }) => theme.media.mobile(css`
top: 40px;
`)};
`;
const ModalContent = styled.div`
+2
View File
@@ -71,6 +71,8 @@ const Window = styled.div`
padding: 20px 24px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
position: relative;
max-height: 90vh;
overflow: auto;
`;
const CloseButton = styled.button`
@@ -141,7 +141,9 @@ const CategoryButton = styled.button<{ $active: boolean; $loading: boolean }>`
cursor: pointer;
transition: background-color 1.2s;
background-color: ${({ $active }) => ($active ? '#0C3B2E' : '#F1FAF0')};
color: ${({ $active }) => ($active ? '#F1FAF0' : '#0C3B2E')};
span {
color: ${({ $active }) => ($active ? '#F1FAF0' : '#0C3B2E')};
}
&:hover {
background-color: ${({ $active }) => ($active ? '#0C3B2E' : '#e4f0de')};
+29 -19
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import {useEffect, useState} from 'react';
import styled from 'styled-components';
export function CookiePopup() {
@@ -28,21 +28,23 @@ export function CookiePopup() {
return (
<Popup $hiding={hiding}>
<IconWrapper>
<img src="/images/cookie.png" alt="Cookie icon" />
</IconWrapper>
<div>
<IconWrapper>
<img src="/images/cookie.png" alt="Cookie icon"/>
</IconWrapper>
<Text>
Мы используем{' '}
<a href="/cookies_and_recommendations.html#c" target="_blank" rel="noreferrer">
куки
</a>{' '}
и{' '}
<a href="/cookies_and_recommendations.html#r" target="_blank" rel="noreferrer">
рекомендательные технологии
</a>
, это помогает улучшать сервис и запоминать ваши настройки
</Text>
<Text>
Мы используем{' '}
<a href="/cookies_and_recommendations.html#c" target="_blank" rel="noreferrer">
куки
</a>{' '}
и{' '}
<a href="/cookies_and_recommendations.html#r" target="_blank" rel="noreferrer">
рекомендательные технологии
</a>
, это помогает улучшать сервис и запоминать ваши настройки
</Text>
</div>
<AcceptButton type="button" onClick={accept}>
Хорошо
@@ -55,7 +57,7 @@ const Popup = styled.div<{ $hiding: boolean }>`
position: fixed;
bottom: 25px;
left: 50%;
transform: translateX(-50%) translateY(${({ $hiding }) => ($hiding ? '30px' : '0')});
transform: translateX(-50%) translateY(${({$hiding}) => ($hiding ? '30px' : '0')});
background: #ffffff;
border-radius: 20px;
border: 2px solid #E7EDE7;
@@ -67,10 +69,16 @@ const Popup = styled.div<{ $hiding: boolean }>`
width: 95%;
max-width: 780px;
z-index: 9999;
opacity: ${({ $hiding }) => ($hiding ? 0 : 1)};
visibility: ${({ $hiding }) => ($hiding ? 'hidden' : 'visible')};
opacity: ${({$hiding}) => ($hiding ? 0 : 1)};
visibility: ${({$hiding}) => ($hiding ? 'hidden' : 'visible')};
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
& > div {
flex-direction: row;
display: flex;
gap: 24px;
}
@media (max-width: 600px) {
flex-wrap: wrap;
justify-content: center;
@@ -108,9 +116,10 @@ const IconWrapper = styled.div`
`;
const Text = styled.p`
display: flex;
margin: 0;
flex-grow: 1;
color: ${({ theme }) => theme.colors.darkGreen};
color: ${({theme}) => theme.colors.darkGreen};
font-size: 14px;
line-height: 20px;
letter-spacing: 0.01em;
@@ -118,6 +127,7 @@ const Text = styled.p`
a {
color: #69a342;
font-weight: 600;
display: contents;
}
@media (max-width: 600px) {
+4 -1
View File
@@ -1,4 +1,4 @@
import styled from 'styled-components';
import styled, {css} from 'styled-components';
interface DaysSectionProps {
value: number;
@@ -27,6 +27,9 @@ export function DaysSection({ value, onChange }: DaysSectionProps) {
const DaysOptions = styled.div`
display: flex;
gap: 12px;
${props => props.theme.media.mobile(css`
gap: 16px;
`)}
`;
const DayButton = styled.button<{ $active: boolean }>`
+28 -7
View File
@@ -1,5 +1,5 @@
import { useState } from 'react';
import styled from 'styled-components';
import styled, {css} from 'styled-components';
import { declension } from '../../utils/declension';
import type { User } from '../../types/user';
import { PersonModal } from './PersonModal';
@@ -39,7 +39,6 @@ export function FamilySection({
{users.map((user, index) => (
<FamilyMember
key={`${user.name}-${index}`}
type="button"
onClick={() => {
setEditingIndex(index);
setIsModalOpen(true);
@@ -65,7 +64,10 @@ export function FamilySection({
handleDelete(index);
}}
>
×
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.167 14.1641L5.83366 5.83073M14.167 5.83073L5.83366 14.1641" stroke="#CEDFD0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</DeleteButton>
</FamilyMember>
))}
@@ -115,17 +117,18 @@ const FamilyList = styled.div`
gap: 12px;
`;
const FamilyMember = styled.button`
const FamilyMember = styled.div`
width: 100%;
display: flex;
align-items: center;
padding: 12px 16px;
align-items: stretch;
padding: 12px 20px;
border: 1px solid ${({ theme }) => theme.colors.border};
border-radius: 12px;
background: #fff;
transition: 0.2s;
cursor: pointer;
text-align: left;
height: 100%;
&:hover {
border-color: #c0c0c0;
@@ -169,28 +172,42 @@ const Info = styled.div`
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
`;
const Name = styled.div`
font-size: 16px;
font-weight: 600;
color: ${({ theme }) => theme.colors.darkGreen};
${props => props.theme.media.mobile(css`
padding-top: 1.5px;
font-size: 14px;
`)}
`;
const Age = styled.div`
font-size: 16px;
font-weight: 350;
color: ${({ theme }) => theme.colors.gray};
* {
color: inherit;
}
${props => props.theme.media.mobile(css`
font-size: 14px;
padding-bottom: 4.5px;
`)}
`;
const DeleteButton = styled.button`
color: #d1d5db;
cursor: pointer;
font-size: 18px;
padding: 0 8px;
transition: 0.2s;
background: transparent;
border: 0;
width: 20px;
height: 20px;
align-self: center;
&:hover {
color: #e53935;
@@ -220,6 +237,10 @@ const AddButton = styled.button`
background-color: transparent;
border: 0;
span {
color:inherit;
}
&:hover {
background-color: #F7FBF6;
}
+2 -9
View File
@@ -110,7 +110,7 @@ export function PersonModal({
}
return (
<Overlay onClick={onClose}>
<Overlay onClick={() => showExpanded ? setShowExpanded('') : onClose()}>
{showExpanded ? (
<Content onClick={event => event.stopPropagation()}>
<Header>
@@ -245,6 +245,7 @@ const Overlay = styled.div`
justify-content: center;
z-index: 1000;
padding: 20px;
overflow: auto;
`;
const Content = styled.div`
@@ -321,10 +322,6 @@ const FormRow = styled.div`
${FormGroup} {
margin-bottom: 0;
}
@media (max-width: 600px) {
flex-direction: column;
}
`;
const Hint = styled.span`
@@ -365,10 +362,6 @@ const PrefsGrid = styled.div`
border-top: 1px solid #f0f0f0;
padding-top: 16px;
min-height: 200px;
@media (max-width: 600px) {
flex-direction: column;
}
`;
const SaveButton = styled.button`
-36
View File
@@ -90,42 +90,6 @@ export function TagsInput({
);
}
const Overlay = styled.div`
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(2px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 20px;
`;
const Content = styled.div`
background: #ffffff;
border-radius: 24px;
width: 100%;
max-width: 440px;
padding: 24px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2);
max-height: 95vh;
overflow-y: auto;
`;
const Header = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
h2 {
font-size: 20px;
font-weight: 600;
color: ${({ theme }) => theme.colors.darkGreen};
}
`;
const Column = styled.div`
flex: 1;
position: relative;