From 2ab34d76200dfb09e293379bc45d32861191a2b7 Mon Sep 17 00:00:00 2001 From: Mark Melior Date: Wed, 8 Jan 2025 01:21:02 +0300 Subject: [PATCH 1/3] VEES-18 | Refactor `InfoBlock` --- README.md | 10 +- docs/naming-conventions.md | 4 + src/app/(with-navbar)/page.tsx | 48 ++++-- src/app/globals.scss | 4 + src/app/vees/page.tsx | 52 ++++++- src/shared/constants/index.ts | 4 + src/shared/ui/Chip/Chip.tsx | 6 +- src/shared/ui/InfoBlock/InfoBlock.tsx | 57 +++++++ src/shared/ui/InfoBlock/client.ts | 1 + .../ui/InfoBlock}/infoBlock.module.scss | 14 +- src/shared/ui/List/index.tsx | 35 +++++ .../ui/List/ui/Horizontal/Horizontal.tsx | 28 ++++ .../List/ui/Horizontal/horizontal.module.scss | 4 + src/shared/ui/List/ui/Item/Item.tsx | 37 +++++ src/shared/ui/List/ui/Item/item.module.scss | 4 + src/shared/ui/client.ts | 1 + src/shared/ui/index.ts | 1 + .../AddExerciseModal/ui/AddExerciseModal.tsx | 5 +- src/widgets/Card/index.tsx | 9 ++ src/widgets/Card/model/mock.ts | 72 +++++++++ src/widgets/Card/ui/Card/Card.tsx | 44 ++++++ src/widgets/Card/ui/Card/card.module.scss | 39 +++++ .../Card/ui/ExerciseItem/ExerciseItem.tsx | 62 ++++++++ .../ui/ExerciseItem/exerciseItem.module.scss | 0 .../Card/ui/ExerciseList/ExerciseList.tsx | 15 ++ src/widgets/Card/ui/VeesItem/VeesItem.tsx | 146 ++++++++++++++++++ .../ui/VeesItem/veesItem.module.scss | 40 ----- .../ui/VeesList/VeesList.tsx | 7 +- .../ui/VeesList/veesList.module.scss | 0 src/widgets/Headers/index.tsx | 8 +- .../ui/ExercisesList/ExercisesList.tsx | 1 + src/widgets/InfoBlock/client.ts | 1 - src/widgets/InfoBlock/index.ts | 1 - .../InfoBlock/model/mock-exercises.tsx | 36 ----- src/widgets/InfoBlock/model/mock-vees.tsx | 51 ------ src/widgets/InfoBlock/ui/InfoBlock.tsx | 106 ------------- src/widgets/Navbar/ui/Navbar/Navbar.tsx | 2 - .../Navbar/ui/Navbar/navbar.global.scss | 3 - src/widgets/VeesList/client.ts | 1 - src/widgets/VeesList/model/mock.ts | 36 ----- src/widgets/VeesList/ui/VeesItem/VeesItem.tsx | 144 ----------------- 41 files changed, 673 insertions(+), 466 deletions(-) create mode 100644 docs/naming-conventions.md create mode 100644 src/shared/ui/InfoBlock/InfoBlock.tsx create mode 100644 src/shared/ui/InfoBlock/client.ts rename src/{widgets/InfoBlock/ui => shared/ui/InfoBlock}/infoBlock.module.scss (88%) create mode 100644 src/shared/ui/List/index.tsx create mode 100644 src/shared/ui/List/ui/Horizontal/Horizontal.tsx create mode 100644 src/shared/ui/List/ui/Horizontal/horizontal.module.scss create mode 100644 src/shared/ui/List/ui/Item/Item.tsx create mode 100644 src/shared/ui/List/ui/Item/item.module.scss create mode 100644 src/widgets/Card/index.tsx create mode 100644 src/widgets/Card/model/mock.ts create mode 100644 src/widgets/Card/ui/Card/Card.tsx create mode 100644 src/widgets/Card/ui/Card/card.module.scss create mode 100644 src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx create mode 100644 src/widgets/Card/ui/ExerciseItem/exerciseItem.module.scss create mode 100644 src/widgets/Card/ui/ExerciseList/ExerciseList.tsx create mode 100644 src/widgets/Card/ui/VeesItem/VeesItem.tsx rename src/widgets/{VeesList => Card}/ui/VeesItem/veesItem.module.scss (68%) rename src/widgets/{VeesList => Card}/ui/VeesList/VeesList.tsx (79%) rename src/widgets/{VeesList => Card}/ui/VeesList/veesList.module.scss (100%) delete mode 100644 src/widgets/InfoBlock/client.ts delete mode 100644 src/widgets/InfoBlock/index.ts delete mode 100644 src/widgets/InfoBlock/model/mock-exercises.tsx delete mode 100644 src/widgets/InfoBlock/model/mock-vees.tsx delete mode 100644 src/widgets/InfoBlock/ui/InfoBlock.tsx delete mode 100644 src/widgets/Navbar/ui/Navbar/navbar.global.scss delete mode 100644 src/widgets/VeesList/client.ts delete mode 100644 src/widgets/VeesList/model/mock.ts delete mode 100644 src/widgets/VeesList/ui/VeesItem/VeesItem.tsx diff --git a/README.md b/README.md index 6b95cdb..275bacb 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ ⠀ -### 🫡 Общие правила проекта +### 📋✏️ Общие правила проекта #### Архитектура @@ -62,7 +62,9 @@ --- -### 👾 Скрипты +⠀ + +### 🎬📃 Скрипты - `yarn dev` - Запуск в Development режиме; - `yarn build` - Production сборка; @@ -71,7 +73,9 @@ --- -### ⚡️ Архитектура проекта +⠀ + +### 📂⚡️ Архитектура проекта Проект написан в соответствии с архитектурной методологией [Feature-Sliced Design](https://feature-sliced.design/docs/get-started/tutorial) и [AppRouter](https://nextjs.org/docs/app) Next.js 15. diff --git a/docs/naming-conventions.md b/docs/naming-conventions.md new file mode 100644 index 0000000..47d6da3 --- /dev/null +++ b/docs/naming-conventions.md @@ -0,0 +1,4 @@ +- Vees — Тренировка +- All Vees — Все тренировки +- Exercise — Упражнение +- Muscle — Группа мышц \ No newline at end of file diff --git a/src/app/(with-navbar)/page.tsx b/src/app/(with-navbar)/page.tsx index 7f284f9..798344f 100644 --- a/src/app/(with-navbar)/page.tsx +++ b/src/app/(with-navbar)/page.tsx @@ -1,9 +1,10 @@ +import { Card } from '@/widgets/Card'; +import { mockExerciseListItems } from '@/widgets/Card/model/mock'; import { Headers } from '@/widgets/Headers'; -import { InfoBlock } from '@/widgets/InfoBlock/client'; -import { mockInfoBlockExercisesItems } from '@/widgets/InfoBlock/model/mock-exercises'; -import { ArrowLeftIcon, FilterOutlineIcon } from '@/shared/icons'; -import { Badge, Button, Flex, Layout, Separator } from '@/shared/ui'; +import { ArrowLeftIcon, FilterOutlineIcon, StopwatchOutlineIcon } from '@/shared/icons'; +import { Badge, Button, Flex, Layout, List, Separator } from '@/shared/ui'; +import { InfoBlock } from '@/shared/ui/client'; import { FiltersModal } from '@/features/FiltersModal'; import { SortModal } from '@/features/SortModal'; @@ -15,11 +16,36 @@ const Home = () => (
- + + } + title="Расчётное время" + value="~ 1 час 30 минут" + /> + + } + showDivider={false} + title="Пусто" + value="Пусто" + /> + @@ -52,6 +78,10 @@ const Home = () => ( + + + +
); diff --git a/src/app/globals.scss b/src/app/globals.scss index c923f3f..22076b1 100644 --- a/src/app/globals.scss +++ b/src/app/globals.scss @@ -33,4 +33,8 @@ body { :disabled { cursor: not-allowed; +} + +main > *:last-child { + padding-bottom: 180px; } \ No newline at end of file diff --git a/src/app/vees/page.tsx b/src/app/vees/page.tsx index ea6ce07..a5a8da9 100644 --- a/src/app/vees/page.tsx +++ b/src/app/vees/page.tsx @@ -1,10 +1,10 @@ +import { Card } from '@/widgets/Card'; +import { mockVeesListItems } from '@/widgets/Card/model/mock'; import { Headers } from '@/widgets/Headers'; -import { InfoBlock } from '@/widgets/InfoBlock/client'; -import { mockInfoBlockVeesItems } from '@/widgets/InfoBlock/model/mock-vees'; -import { VeesList } from '@/widgets/VeesList/client'; -import { mockVeesListItems } from '@/widgets/VeesList/model/mock'; -import { Layout, Separator } from '@/shared/ui'; +import { PaperOutlineIcon, StopwatchOutlineIcon } from '@/shared/icons'; +import { Chip, Layout, List, Separator } from '@/shared/ui'; +import { InfoBlock } from '@/shared/ui/client'; import { Timer } from '@/features/Timer/client'; @@ -13,11 +13,49 @@ const Vees = () => (
- + + } + title="Расчётное время" + value="~ 1 час 30 минут" + /> + } + title="Тренировка" + value={( + + )} + /> + + - +
diff --git a/src/shared/constants/index.ts b/src/shared/constants/index.ts index a382098..32da72b 100644 --- a/src/shared/constants/index.ts +++ b/src/shared/constants/index.ts @@ -1 +1,5 @@ export * from './routes'; + +export const getErrorGroupDirectly = (text: string) => { + throw new Error(`The \'${text}\' component is a group and cannot be used directly.`); +}; diff --git a/src/shared/ui/Chip/Chip.tsx b/src/shared/ui/Chip/Chip.tsx index 4212b10..1a32bfd 100644 --- a/src/shared/ui/Chip/Chip.tsx +++ b/src/shared/ui/Chip/Chip.tsx @@ -19,7 +19,7 @@ export const Chip = ({ children, className, size = 'small' }: IChip) => ( interface ICategory extends IChip { color?: TailwindColors - isEditable?: boolean + isEdited?: boolean name: string number?: number } @@ -27,7 +27,7 @@ interface ICategory extends IChip { const Category = ({ className, color, - isEditable, + isEdited, name, number, size, @@ -35,7 +35,7 @@ const Category = ({ {number && {`${number}.`}} {name} - {isEditable && (изм.)} + {isEdited && (изм.)} ); diff --git a/src/shared/ui/InfoBlock/InfoBlock.tsx b/src/shared/ui/InfoBlock/InfoBlock.tsx new file mode 100644 index 0000000..da30b6a --- /dev/null +++ b/src/shared/ui/InfoBlock/InfoBlock.tsx @@ -0,0 +1,57 @@ +'use client'; + +import { clsx } from 'clsx'; +import { useEffect, useRef, useState } from 'react'; + +import { Background, Button } from '@/shared/ui'; + +import styles from './infoBlock.module.scss'; + +interface IInfoBlock { + children: React.ReactNode + maxHeight?: number + textButton?: string +} + +export const InfoBlock = ({ + children, + maxHeight, + textButton = 'Показать все', +}: IInfoBlock) => { + const [showAll, setShowAll] = useState(false); + const wrapperRef = useRef(null); + + const defaultMaxHeight = maxHeight ?? 999; + + useEffect(() => { + if (!wrapperRef.current) { + return; + } + + wrapperRef.current.style.setProperty( + '--info-block-height', `${showAll ? wrapperRef.current.scrollHeight : defaultMaxHeight}px`, + ); + }, [defaultMaxHeight, showAll]); + + return ( + +
+ {children} +
+ {maxHeight ? ( + + ) : null} +
+ ); +}; diff --git a/src/shared/ui/InfoBlock/client.ts b/src/shared/ui/InfoBlock/client.ts new file mode 100644 index 0000000..0b11683 --- /dev/null +++ b/src/shared/ui/InfoBlock/client.ts @@ -0,0 +1 @@ +export { InfoBlock } from './InfoBlock'; diff --git a/src/widgets/InfoBlock/ui/infoBlock.module.scss b/src/shared/ui/InfoBlock/infoBlock.module.scss similarity index 88% rename from src/widgets/InfoBlock/ui/infoBlock.module.scss rename to src/shared/ui/InfoBlock/infoBlock.module.scss index 82e8145..34f7068 100644 --- a/src/widgets/InfoBlock/ui/infoBlock.module.scss +++ b/src/shared/ui/InfoBlock/infoBlock.module.scss @@ -6,7 +6,7 @@ animation: var(--anim-scale-fade-in); - &.isShowAll { + &.showButton { padding-bottom: 0; } } @@ -14,21 +14,15 @@ .wrapper { --info-block-height: 125px; height: var(--info-block-height); + max-height: fit-content; + padding-right: 16px; + padding-left: 16px; overflow: clip; transition: all 0.3s ease; } -.item { - padding: 6px 16px; -} - -.divider { - margin-right: 16px; - margin-left: 16px; -} - .button { position: sticky; bottom: 0; diff --git a/src/shared/ui/List/index.tsx b/src/shared/ui/List/index.tsx new file mode 100644 index 0000000..c215a03 --- /dev/null +++ b/src/shared/ui/List/index.tsx @@ -0,0 +1,35 @@ +import { getErrorGroupDirectly } from '@/shared/constants'; + +import { ListHorizontal } from './ui/Horizontal/Horizontal'; +import { ListItem } from './ui/Item/Item'; + +// interface IList { +// items: IListHorizontalItem[][] | IListItem[] +// } + +// export const List = ({ items }: IList) => ( +// items.map((item, index) => ( +// <> +// {'icon' in item ? ( +// +// ) : ( +// +// )} +// {index !== items.length - 1 ? : null} +// +// )) +// ); + +export const List = () => getErrorGroupDirectly('List'); + +List.Item = ListItem; +List.Horizontal = ListHorizontal; diff --git a/src/shared/ui/List/ui/Horizontal/Horizontal.tsx b/src/shared/ui/List/ui/Horizontal/Horizontal.tsx new file mode 100644 index 0000000..76cf6f3 --- /dev/null +++ b/src/shared/ui/List/ui/Horizontal/Horizontal.tsx @@ -0,0 +1,28 @@ +import { Divider, Flex, Text } from '@/shared/ui'; + +import styles from './horizontal.module.scss'; + +export interface IListHorizontalItem { + title: string + value: string +} + +interface IListHorizontal { + className?: string + items: IListHorizontalItem[] + showDivider?: boolean +} + +export const ListHorizontal = ({ className, items, showDivider = true }: IListHorizontal) => ( +
+ + {items.map(({ title, value }) => ( + + {title} + {value} + + ))} + + {showDivider ? : null} +
+); diff --git a/src/shared/ui/List/ui/Horizontal/horizontal.module.scss b/src/shared/ui/List/ui/Horizontal/horizontal.module.scss new file mode 100644 index 0000000..e79ce70 --- /dev/null +++ b/src/shared/ui/List/ui/Horizontal/horizontal.module.scss @@ -0,0 +1,4 @@ +.wrapper { + padding-top: 6px; + padding-bottom: 6px; +} \ No newline at end of file diff --git a/src/shared/ui/List/ui/Item/Item.tsx b/src/shared/ui/List/ui/Item/Item.tsx new file mode 100644 index 0000000..b153884 --- /dev/null +++ b/src/shared/ui/List/ui/Item/Item.tsx @@ -0,0 +1,37 @@ +import { Divider, Flex, Text } from '@/shared/ui'; + +import styles from './item.module.scss'; + +export interface IListItem { + className?: string + description?: string + icon: React.ReactNode + showDivider?: boolean + title: string + value: React.ReactNode +} + +export const ListItem = ({ + className, + description, + icon, + showDivider = true, + title, + value, +}: IListItem) => ( +
+ + + + {icon} + {title} + + + + {value} + {description ? {description} : null} + + + {showDivider ? : null} +
+); diff --git a/src/shared/ui/List/ui/Item/item.module.scss b/src/shared/ui/List/ui/Item/item.module.scss new file mode 100644 index 0000000..e79ce70 --- /dev/null +++ b/src/shared/ui/List/ui/Item/item.module.scss @@ -0,0 +1,4 @@ +.wrapper { + padding-top: 6px; + padding-bottom: 6px; +} \ No newline at end of file diff --git a/src/shared/ui/client.ts b/src/shared/ui/client.ts index 7f30899..4db2590 100644 --- a/src/shared/ui/client.ts +++ b/src/shared/ui/client.ts @@ -1,2 +1,3 @@ export * from './Image/client'; +export * from './InfoBlock/client'; export * from './Modal/client'; diff --git a/src/shared/ui/index.ts b/src/shared/ui/index.ts index f77676c..2ef6e1f 100644 --- a/src/shared/ui/index.ts +++ b/src/shared/ui/index.ts @@ -11,6 +11,7 @@ export * from './Icon'; export * from './Input'; export * from './Layout'; export * from './Light'; +export * from './List'; export * from './Loading'; export * from './Modal'; export * from './Section'; diff --git a/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx b/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx index b721922..ba02288 100644 --- a/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx +++ b/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx @@ -133,10 +133,7 @@ export const AddExerciseModal = ({ items }: IAddExerciseModal) => { {item.name} - + {getCountExerciseWord(item.exercises.length)} diff --git a/src/widgets/Card/index.tsx b/src/widgets/Card/index.tsx new file mode 100644 index 0000000..400cf48 --- /dev/null +++ b/src/widgets/Card/index.tsx @@ -0,0 +1,9 @@ +import { getErrorGroupDirectly } from '@/shared/constants'; + +import { ExerciseList } from './ui/ExerciseList/ExerciseList'; +import { VeesList } from './ui/VeesList/VeesList'; + +export const Card = () => getErrorGroupDirectly('Card'); + +Card.VeesList = VeesList; +Card.ExercisesList = ExerciseList; diff --git a/src/widgets/Card/model/mock.ts b/src/widgets/Card/model/mock.ts new file mode 100644 index 0000000..ea422ac --- /dev/null +++ b/src/widgets/Card/model/mock.ts @@ -0,0 +1,72 @@ +import { ICardExerciseItem } from '../ui/ExerciseItem/ExerciseItem'; +import { ICardVeesItem } from '../ui/VeesItem/VeesItem'; + +export const mockVeesListItems: ICardVeesItem[] = [ + { + comment: 'Это некая заметка к упражнению на будущее, а может просто по приколу. Я не знаю', + groupColor: '#FAC938', + groupName: 'Спина', + name: 'Горизонтальная тяга', + previousResult: [ + { count: 10, weight: 30 }, + { count: 7, weight: 30 }, + { count: 10, weight: 28 }, + ], + result: [ + { count: 10, weight: 30 }, + { count: 6, weight: 32 }, + { count: 11, weight: 25 }, + ], + }, + { + groupColor: '#FA4838', + groupName: 'Средние дельты', + name: 'Разведения в кроссовере', + previousName: 'Жим гантелей', + previousResult: [{ count: 14, weight: 20 }], + result: [{ count: 12, weight: 20 }], + }, + { + groupColor: '#1A80E5', + groupName: 'Грудь', + name: 'Жим лежа на наклонной скамье', + previousName: 'Жим гантелей', + previousResult: [{ count: 6, weight: 80 }, { count: 4, weight: 80 }], + result: [{ count: 6, weight: 80 }, { count: 2, weight: 90 }], + }, +]; + +export const mockExerciseListItems: ICardExerciseItem[] = [ + { + comment: 'Это некая заметка к упражнению на будущее, а может просто по приколу. Я не знаю', + groupColor: '#FAC938', + groupName: 'Спина', + name: 'Горизонтальная тяга', + previousResult: [ + { count: 10, weight: 30 }, + { count: 7, weight: 30 }, + { count: 10, weight: 28 }, + ], + result: [ + { count: 10, weight: 30 }, + { count: 6, weight: 32 }, + { count: 11, weight: 25 }, + ], + }, + { + groupColor: '#FA4838', + groupName: 'Средние дельты', + name: 'Разведения в кроссовере', + previousName: 'Жим гантелей', + previousResult: [{ count: 14, weight: 20 }], + result: [{ count: 12, weight: 20 }], + }, + { + groupColor: '#1A80E5', + groupName: 'Грудь', + name: 'Жим лежа на наклонной скамье', + previousName: 'Жим гантелей', + previousResult: [{ count: 6, weight: 80 }, { count: 4, weight: 80 }], + result: [{ count: 6, weight: 80 }, { count: 2, weight: 90 }], + }, +]; diff --git a/src/widgets/Card/ui/Card/Card.tsx b/src/widgets/Card/ui/Card/Card.tsx new file mode 100644 index 0000000..b5f1fd7 --- /dev/null +++ b/src/widgets/Card/ui/Card/Card.tsx @@ -0,0 +1,44 @@ +import { clsx } from 'clsx'; +import { Dispatch, SetStateAction } from 'react'; + +import { ArrowDropdownIcon } from '@/shared/icons'; +import { Background, Button, Flex } from '@/shared/ui'; + +import styles from './card.module.scss'; + +interface ICard { + children: React.ReactNode + chipList?: React.ReactNode + isOpen: boolean | null + leftAction?: React.ReactNode + setIsOpen: Dispatch> +} + +export const Card = ({ + children, + chipList, + isOpen, + leftAction, + setIsOpen, +}: ICard) => ( + + {leftAction} + + + {chipList} + + {children} + + + +); diff --git a/src/widgets/Card/ui/Card/card.module.scss b/src/widgets/Card/ui/Card/card.module.scss new file mode 100644 index 0000000..ab162bc --- /dev/null +++ b/src/widgets/Card/ui/Card/card.module.scss @@ -0,0 +1,39 @@ +.wrapper { + display: flex; + + animation: var(--anim-scale-fade-in); + + @media (max-width: theme('screens.sm')) { + border-radius: .75rem 0 0 .75rem; + } +} + +.content { + position: relative; + padding: 15px 10px 15px 0; +} + +.chipList { + position: absolute; + top: -12px; + + color: theme('colors.base.600'); +} + +.buttonShow { + width: 64px; + height: auto; + + &.collapsed { + color: theme('colors.base.600'); + background: theme('colors.base.800'); + + &:hover { + background: theme('colors.base.700') !important; + } + } + + @media (max-width: theme('screens.sm')) { + border-radius: .75rem 0 0 .75rem; + } +} \ No newline at end of file diff --git a/src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx b/src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx new file mode 100644 index 0000000..3b56a0c --- /dev/null +++ b/src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx @@ -0,0 +1,62 @@ +'use client'; + +import { useState } from 'react'; + +import { MessageIcon } from '@/shared/icons'; +import { Chip, Text } from '@/shared/ui'; + +import { Card } from '../Card/Card'; + +import styles from './exerciseItem.module.scss'; + +interface IVeesRecord { + count: number + weight: number +} + +export interface ICardExerciseItem { + comment?: string + groupColor?: string + groupName?: string + name: string + previousName?: string + previousResult?: IVeesRecord[] + result?: IVeesRecord[] +} + +interface IExerciseItem { + item: ICardExerciseItem +} + +export const ExerciseItem = ({ item }: IExerciseItem) => { + const [isOpen, setIsOpen] = useState(null); + + const { + comment, + } = item; + + return ( + + 12 ноября 2024 + {comment ? ( + + + 3 + + ) : null} + + )} + isOpen={isOpen} + leftAction={( + + )} + setIsOpen={setIsOpen} + > + HI + + ); +}; diff --git a/src/widgets/Card/ui/ExerciseItem/exerciseItem.module.scss b/src/widgets/Card/ui/ExerciseItem/exerciseItem.module.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/widgets/Card/ui/ExerciseList/ExerciseList.tsx b/src/widgets/Card/ui/ExerciseList/ExerciseList.tsx new file mode 100644 index 0000000..29e0744 --- /dev/null +++ b/src/widgets/Card/ui/ExerciseList/ExerciseList.tsx @@ -0,0 +1,15 @@ +import { Flex } from '@/shared/ui'; + +import { ICardExerciseItem, ExerciseItem } from '../ExerciseItem/ExerciseItem'; + +interface IExerciseList { + items: ICardExerciseItem[] +} + +export const ExerciseList = ({ items }: IExerciseList) => ( + + {items.map((item, index) => ( + + ))} + +); diff --git a/src/widgets/Card/ui/VeesItem/VeesItem.tsx b/src/widgets/Card/ui/VeesItem/VeesItem.tsx new file mode 100644 index 0000000..b9c953c --- /dev/null +++ b/src/widgets/Card/ui/VeesItem/VeesItem.tsx @@ -0,0 +1,146 @@ +'use client'; + +import { clsx } from 'clsx'; +import { useState } from 'react'; + +import { DragIcon, MessageIcon, PlusIcon } from '@/shared/icons'; +import { Button, Chip, Flex, Text } from '@/shared/ui'; + +import { Card } from '../Card/Card'; + +import styles from './veesItem.module.scss'; + +interface IVeesRecord { + count: number + weight: number +} + +export interface ICardVeesItem { + comment?: string + groupColor?: string + groupName?: string + name: string + previousName?: string + previousResult?: IVeesRecord[] + result?: IVeesRecord[] +} + +interface IVeesItem { + item: ICardVeesItem +} + +export const VeesItem = ({ item }: IVeesItem) => { + const [isOpen, setIsOpen] = useState(null); + + const { + comment, + groupColor, + groupName, + name, + previousName, + previousResult, + result, + } = item; + + const animationStyle = isOpen !== null + ? (isOpen ? styles.fadeUp : styles.fadeDown) : undefined; + + return ( + + {groupName} + {comment ? : null} + + )} + isOpen={isOpen} + leftAction={( + + )} + setIsOpen={setIsOpen} + > + + {name} + {previousName ? ( + + {previousName} + + ) : null} + {comment ? ( + + {comment} + + ) : null} + + + {result?.map(({ count, weight }, index) => { + const previousWeight = previousResult?.[index]?.weight ?? 0; + const previousCount = previousResult?.[index]?.count ?? 0; + + const isBetter = weight > previousWeight + || (weight === previousWeight && count > previousCount); + const isWorse = weight < previousWeight || count < previousCount; + + return ( + // TODO: Добавление подхода в VeesList - https://melior-app.atlassian.net/browse/VEES-12 + + ); + })} + + + {previousResult?.length ? ( + + + Прошлый результат: + + + {previousResult.map(({ count, weight }, index) => ( + + ))} + + + ) : null} + + ); +}; diff --git a/src/widgets/VeesList/ui/VeesItem/veesItem.module.scss b/src/widgets/Card/ui/VeesItem/veesItem.module.scss similarity index 68% rename from src/widgets/VeesList/ui/VeesItem/veesItem.module.scss rename to src/widgets/Card/ui/VeesItem/veesItem.module.scss index f64c6a4..830bceb 100644 --- a/src/widgets/VeesList/ui/VeesItem/veesItem.module.scss +++ b/src/widgets/Card/ui/VeesItem/veesItem.module.scss @@ -1,43 +1,3 @@ -.wrapper { - display: flex; - - animation: var(--anim-scale-fade-in); - - @media (max-width: theme('screens.sm')) { - border-radius: .75rem 0 0 .75rem; - } -} - -.content { - position: relative; - padding: 15px 10px 15px 0; -} - -.chipList { - position: absolute; - top: -12px; - - color: theme('colors.base.600'); -} - -.buttonShow { - width: 64px; - height: auto; - - &.collapsed { - color: theme('colors.base.600'); - background: theme('colors.base.800'); - - &:hover { - background: theme('colors.base.700') !important; - } - } - - @media (max-width: theme('screens.sm')) { - border-radius: .75rem 0 0 .75rem; - } -} - .button { gap: 2; min-width: 80px; diff --git a/src/widgets/VeesList/ui/VeesList/VeesList.tsx b/src/widgets/Card/ui/VeesList/VeesList.tsx similarity index 79% rename from src/widgets/VeesList/ui/VeesList/VeesList.tsx rename to src/widgets/Card/ui/VeesList/VeesList.tsx index e761759..6ef5cdd 100644 --- a/src/widgets/VeesList/ui/VeesList/VeesList.tsx +++ b/src/widgets/Card/ui/VeesList/VeesList.tsx @@ -1,14 +1,12 @@ -'use client'; - import { FinishOutlineIcon } from '@/shared/icons'; import { Button, Flex } from '@/shared/ui'; -import { IVeesItem, VeesItem } from '../VeesItem/VeesItem'; +import { ICardVeesItem, VeesItem } from '../VeesItem/VeesItem'; import styles from './veesList.module.scss'; interface IVeesList { - items: IVeesItem[] + items: ICardVeesItem[] } export const VeesList = ({ items }: IVeesList) => ( @@ -16,6 +14,7 @@ export const VeesList = ({ items }: IVeesList) => ( {items.map((item, index) => ( ))} + {/* TODO: Вынести кнопку в features */} + {/* TODO: Вынести кнопку в features */} diff --git a/src/widgets/InfoBlock/client.ts b/src/widgets/InfoBlock/client.ts deleted file mode 100644 index 3499900..0000000 --- a/src/widgets/InfoBlock/client.ts +++ /dev/null @@ -1 +0,0 @@ -export { InfoBlock } from './ui/InfoBlock'; diff --git a/src/widgets/InfoBlock/index.ts b/src/widgets/InfoBlock/index.ts deleted file mode 100644 index dd5333f..0000000 --- a/src/widgets/InfoBlock/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { IInfoBlockItem } from './ui/InfoBlock'; diff --git a/src/widgets/InfoBlock/model/mock-exercises.tsx b/src/widgets/InfoBlock/model/mock-exercises.tsx deleted file mode 100644 index 85e0fea..0000000 --- a/src/widgets/InfoBlock/model/mock-exercises.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { IInfoBlockItem } from '@/widgets/InfoBlock'; - -import { StopwatchOutlineIcon } from '@/shared/icons'; -import { Flex, Text } from '@/shared/ui'; - -export const mockInfoBlockExercisesItems: IInfoBlockItem[] = [ - { - icon: , - title: 'Вы тренировались', - value: 148 часов 56 минут, - }, - { - hideTitle: true, - title: 'Статистика', - value: ( - - - Тренировок - 98 - - - Подходов - 1787 - - - Стаж - 1 год - - - ), - }, - { - title: 'Ничего', - value: 'И тут ничего', - }, -]; diff --git a/src/widgets/InfoBlock/model/mock-vees.tsx b/src/widgets/InfoBlock/model/mock-vees.tsx deleted file mode 100644 index be92bca..0000000 --- a/src/widgets/InfoBlock/model/mock-vees.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { IInfoBlockItem } from '@/widgets/InfoBlock'; - -import { PaperOutlineIcon, StopwatchOutlineIcon } from '@/shared/icons'; -import { Chip, Flex, Text } from '@/shared/ui'; - -export const mockInfoBlockVeesItems: IInfoBlockItem[] = [ - { - icon: , - title: 'Расчётное время', - value: ( - - ~ 1 час 30 минут - ~ конец в 18:36 - - ), - }, - { - icon: , - title: 'Тренировка', - value: ( - - ), - }, - { - hideTitle: true, - title: 'Статистика', - value: ( - - - Тренировка № - 98 - - - Начало - 17:06 - - - Упражнений - 7 - - - ), - }, -]; diff --git a/src/widgets/InfoBlock/ui/InfoBlock.tsx b/src/widgets/InfoBlock/ui/InfoBlock.tsx deleted file mode 100644 index 65a3df8..0000000 --- a/src/widgets/InfoBlock/ui/InfoBlock.tsx +++ /dev/null @@ -1,106 +0,0 @@ -'use client'; - -import { clsx } from 'clsx'; -import { Fragment, useEffect, useRef, useState } from 'react'; - -import { Background, Button, Divider, Flex, Text } from '@/shared/ui'; - -import styles from './infoBlock.module.scss'; - -export interface IInfoBlockItem { - hideTitle?: boolean - icon?: React.ReactNode - title: string - value: React.ReactNode -} - -interface IInfoBlock { - items: IInfoBlockItem[] - showAllCountItems?: number - showAllText?: string -} - -export const InfoBlock = ({ - items, - showAllCountItems = 3, - showAllText = 'Показать все', -}: IInfoBlock) => { - const [showAll, setShowAll] = useState(false); - const wrapperRef = useRef(null); - - const isShowAll = items.length > showAllCountItems; - - useEffect(() => { - if (!wrapperRef.current) { - return; - } - - // Если showAll активен, берем полную высоту элемента - if (showAll) { - const fullHeight = wrapperRef.current.scrollHeight; - - wrapperRef.current.style.setProperty('--info-block-height', `${fullHeight}px`); - - return; - } - - // Получение всех элементов Flex и Divider - const itemElements = wrapperRef.current.querySelectorAll(`.${styles.item}`); - const dividerElements = wrapperRef.current.querySelectorAll(`.${styles.divider}`); - - // Рассчитываем общую высоту для ограниченного количества элементов - let totalHeight = 0; - - for (let i = 0; i < showAllCountItems; i++) { - if (itemElements[i]) { - totalHeight += itemElements[i].clientHeight; - } - if (dividerElements[i] && i < showAllCountItems - 1) { - totalHeight += dividerElements[i].clientHeight || 12; - } - } - - // Устанавливаем CSS-переменную - wrapperRef.current.style.setProperty('--info-block-height', `${totalHeight}px`); - }, [showAll, showAllCountItems, items.length]); - - if (!items.length) { - return null; - } - - return ( - -
- {items.map(({ hideTitle, icon, title, value }, index) => ( - - - {hideTitle ? null : ( - - - {icon} - {title} - - - )} - {value} - - {index !== items.length - 1 ? : null} - - ))} -
- {isShowAll ? ( - - ) : null} -
- ); -}; diff --git a/src/widgets/Navbar/ui/Navbar/Navbar.tsx b/src/widgets/Navbar/ui/Navbar/Navbar.tsx index e0867b6..fc6694a 100644 --- a/src/widgets/Navbar/ui/Navbar/Navbar.tsx +++ b/src/widgets/Navbar/ui/Navbar/Navbar.tsx @@ -12,8 +12,6 @@ import { BackActiveVees } from '../BackActiveVees/BackActiveVees'; import styles from './navbar.module.scss'; -import './navbar.global.scss'; - interface IBaseNavbarItem { disabled?: boolean icon: React.ReactNode diff --git a/src/widgets/Navbar/ui/Navbar/navbar.global.scss b/src/widgets/Navbar/ui/Navbar/navbar.global.scss deleted file mode 100644 index e00d5ef..0000000 --- a/src/widgets/Navbar/ui/Navbar/navbar.global.scss +++ /dev/null @@ -1,3 +0,0 @@ -main > *:last-child { - padding-bottom: 160px; -} \ No newline at end of file diff --git a/src/widgets/VeesList/client.ts b/src/widgets/VeesList/client.ts deleted file mode 100644 index 0d52722..0000000 --- a/src/widgets/VeesList/client.ts +++ /dev/null @@ -1 +0,0 @@ -export { VeesList } from './ui/VeesList/VeesList'; diff --git a/src/widgets/VeesList/model/mock.ts b/src/widgets/VeesList/model/mock.ts deleted file mode 100644 index 47f5cc5..0000000 --- a/src/widgets/VeesList/model/mock.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { IVeesItem } from '../ui/VeesItem/VeesItem'; - -export const mockVeesListItems: IVeesItem[] = [ - { - comment: 'Это некая заметка к упражнению на будущее, а может просто по приколу. Я не знаю', - groupColor: '#FAC938', - groupName: 'Спина', - name: 'Горизонтальная тяга', - previousResult: [ - { count: 10, weight: 30 }, - { count: 7, weight: 30 }, - { count: 10, weight: 28 }, - ], - result: [ - { count: 10, weight: 30 }, - { count: 6, weight: 32 }, - { count: 11, weight: 25 }, - ], - }, - { - groupColor: '#FA4838', - groupName: 'Средние дельты', - name: 'Разведения в кроссовере', - previousName: 'Жим гантелей', - previousResult: [{ count: 14, weight: 20 }], - result: [{ count: 12, weight: 20 }], - }, - { - groupColor: '#1A80E5', - groupName: 'Грудь', - name: 'Жим лежа на наклонной скамье', - previousName: 'Жим гантелей', - previousResult: [{ count: 6, weight: 80 }, { count: 4, weight: 80 }], - result: [{ count: 6, weight: 80 }, { count: 2, weight: 90 }], - }, -]; diff --git a/src/widgets/VeesList/ui/VeesItem/VeesItem.tsx b/src/widgets/VeesList/ui/VeesItem/VeesItem.tsx deleted file mode 100644 index 4c793a9..0000000 --- a/src/widgets/VeesList/ui/VeesItem/VeesItem.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { clsx } from 'clsx'; -import { useState } from 'react'; - -import { ArrowDropdownIcon, DragIcon, MessageIcon, PlusIcon } from '@/shared/icons'; -import { Background, Button, Chip, Flex, Text } from '@/shared/ui'; - -import styles from './veesItem.module.scss'; - -interface IVeesRecord { - count: number - weight: number -} - -export interface IVeesItem { - comment?: string - groupColor?: string - groupName?: string - name: string - previousName?: string - previousResult?: IVeesRecord[] - result?: IVeesRecord[] -} - -export const VeesItem = ({ item }: { item: IVeesItem }) => { - const [isOpen, setIsOpen] = useState(null); - - const { - comment, - groupColor, - groupName, - name, - previousName, - previousResult, - result, - } = item; - - const animationStyle = isOpen !== null - ? (isOpen ? styles.fadeUp : styles.fadeDown) : undefined; - - return ( - - - - - {groupName} - {comment ? : null} - - - {name} - {previousName ? ( - - {previousName} - - ) : null} - {comment ? ( - - {comment} - - ) : null} - - - {result?.map(({ count, weight }, index) => { - const previousWeight = previousResult?.[index]?.weight ?? 0; - const previousCount = previousResult?.[index]?.count ?? 0; - - const isBetter = weight > previousWeight - || (weight === previousWeight && count > previousCount); - const isWorse = weight < previousWeight || count < previousCount; - - return ( - // TODO: Добавление подхода в VeesList - https://melior-app.atlassian.net/browse/VEES-12 - - ); - })} - - - {previousResult?.length ? ( - - - Прошлый результат: - - - {previousResult.map(({ count, weight }, index) => ( - - ))} - - - ) : null} - - - - ); -}; From e9ff3082c4dc46696cf7f2094ab87080d9efa93b Mon Sep 17 00:00:00 2001 From: Mark Melior Date: Wed, 8 Jan 2025 10:52:05 +0300 Subject: [PATCH 2/3] VEES-18 | Refactor `InfoBlock` --- docs/naming-conventions.md | 4 +- eslint.config.mjs | 15 +++ src/features/Timer/ui/Timer.tsx | 2 +- src/shared/icons/add-outline.tsx | 3 +- src/shared/icons/arrow-dropdown.tsx | 3 +- src/shared/icons/arrow-left.tsx | 3 +- src/shared/icons/cross.tsx | 3 +- src/shared/icons/drag.tsx | 3 +- src/shared/icons/export-outline.tsx | 3 +- src/shared/icons/filter-outline.tsx | 3 +- src/shared/icons/finish-outline.tsx | 3 +- src/shared/icons/flash-outline.tsx | 3 +- src/shared/icons/folder-outline.tsx | 3 +- src/shared/icons/import-outline.tsx | 3 +- src/shared/icons/lang.tsx | 3 +- src/shared/icons/logo.tsx | 3 +- src/shared/icons/message.tsx | 3 +- src/shared/icons/paper-outline.tsx | 3 +- src/shared/icons/pause.tsx | 3 +- src/shared/icons/play.tsx | 3 +- src/shared/icons/plus.tsx | 3 +- src/shared/icons/reset.tsx | 3 +- src/shared/icons/setting-outline.tsx | 3 +- src/shared/icons/stopwatch-outline.tsx | 3 +- src/shared/icons/theme.tsx | 3 +- src/shared/icons/user.tsx | 3 +- src/shared/icons/vees.tsx | 3 +- src/shared/lib/date.ts | 101 ++++++++++++++ src/shared/lib/utils.ts | 25 ---- src/shared/types/index.ts | 5 +- src/shared/ui/Background/Background.tsx | 2 +- src/shared/ui/Button/Button.tsx | 2 +- src/shared/ui/Chip/Chip.tsx | 19 ++- src/shared/ui/Flex/Flex.tsx | 2 +- src/shared/ui/Header/utils/CurrentDate.tsx | 2 +- src/shared/ui/Icon/Icon.tsx | 4 +- src/shared/ui/Layout/Layout.tsx | 2 +- .../ui/List/ui/Horizontal/Horizontal.tsx | 2 +- src/shared/ui/Loading/Loading.tsx | 2 +- src/shared/ui/Modal/ui/Base/Base.tsx | 4 +- src/shared/ui/Section/Section.tsx | 2 +- src/shared/ui/Text/Text.tsx | 2 +- src/widgets/AddExerciseModal/model/mock.ts | 2 +- .../AddExerciseModal/ui/AddExerciseModal.tsx | 2 +- src/widgets/Card/model/mock.ts | 61 ++++----- src/widgets/Card/ui/Card/Card.tsx | 7 +- src/widgets/Card/ui/Card/card.module.scss | 4 + .../Card/ui/ExerciseItem/ExerciseItem.tsx | 124 ++++++++++++++---- .../ui/ExerciseItem/exerciseItem.module.scss | 12 ++ .../Card/ui/ExerciseList/ExerciseList.tsx | 7 +- .../Card/ui/VeesItem/veesItem.module.scss | 7 +- src/widgets/Card/ui/VeesList/VeesList.tsx | 4 +- src/widgets/Navbar/ui/Navbar/Navbar.tsx | 2 +- 53 files changed, 367 insertions(+), 134 deletions(-) create mode 100644 src/shared/lib/date.ts delete mode 100644 src/shared/lib/utils.ts diff --git a/docs/naming-conventions.md b/docs/naming-conventions.md index 47d6da3..f4bed7f 100644 --- a/docs/naming-conventions.md +++ b/docs/naming-conventions.md @@ -1,4 +1,6 @@ - Vees — Тренировка - All Vees — Все тренировки - Exercise — Упражнение -- Muscle — Группа мышц \ No newline at end of file +- Muscle — Группа мышц +- Vees Template - Шаблон тренировки +- Approach - Подход \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index 0451ed1..2b470e1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -49,6 +49,14 @@ const eslintCommonRules = { }, { blankLine: 'always', next: 'return', prev: '*' }, ], + 'sort-imports': [ + 'error', + { + ignoreCase: false, + ignoreDeclarationSort: true, + ignoreMemberSort: false, + }, + ], }; const eslintReactRules = { @@ -63,6 +71,13 @@ const eslintReactRules = { }; const eslintTypescriptRules = { + '@typescript-eslint/consistent-type-imports': [ + 'error', + { + disallowTypeAnnotations: false, // Позволяет аннотации через `import type` + prefer: 'type-imports', // Всегда использовать "import type" для типов + }, + ], '@typescript-eslint/no-unused-vars': 'error', }; diff --git a/src/features/Timer/ui/Timer.tsx b/src/features/Timer/ui/Timer.tsx index 23b40a0..e8e2c4d 100644 --- a/src/features/Timer/ui/Timer.tsx +++ b/src/features/Timer/ui/Timer.tsx @@ -1,7 +1,7 @@ 'use client'; import { clsx } from 'clsx'; -import { useState, useEffect, useCallback, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { PauseIcon, PlayIcon, StopwatchOutlineIcon } from '@/shared/icons'; import { Background, Button, Flex, Layout, Text } from '@/shared/ui'; diff --git a/src/shared/icons/add-outline.tsx b/src/shared/icons/add-outline.tsx index f4eaec6..e91ce62 100644 --- a/src/shared/icons/add-outline.tsx +++ b/src/shared/icons/add-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const AddOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/arrow-dropdown.tsx b/src/shared/icons/arrow-dropdown.tsx index 2832242..6d02046 100644 --- a/src/shared/icons/arrow-dropdown.tsx +++ b/src/shared/icons/arrow-dropdown.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const ArrowDropdownIcon = ({ className, diff --git a/src/shared/icons/arrow-left.tsx b/src/shared/icons/arrow-left.tsx index 6fb72fb..724af3a 100644 --- a/src/shared/icons/arrow-left.tsx +++ b/src/shared/icons/arrow-left.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const ArrowLeftIcon = ({ className, diff --git a/src/shared/icons/cross.tsx b/src/shared/icons/cross.tsx index da92f13..0e50c6e 100644 --- a/src/shared/icons/cross.tsx +++ b/src/shared/icons/cross.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const CrossIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/drag.tsx b/src/shared/icons/drag.tsx index e7f3f27..62d6475 100644 --- a/src/shared/icons/drag.tsx +++ b/src/shared/icons/drag.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const DragIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/export-outline.tsx b/src/shared/icons/export-outline.tsx index e517afb..1bb3c0e 100644 --- a/src/shared/icons/export-outline.tsx +++ b/src/shared/icons/export-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const ExportOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/filter-outline.tsx b/src/shared/icons/filter-outline.tsx index 7dd314d..3620b0f 100644 --- a/src/shared/icons/filter-outline.tsx +++ b/src/shared/icons/filter-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const FilterOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/finish-outline.tsx b/src/shared/icons/finish-outline.tsx index 06f6d21..47d7330 100644 --- a/src/shared/icons/finish-outline.tsx +++ b/src/shared/icons/finish-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const FinishOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/flash-outline.tsx b/src/shared/icons/flash-outline.tsx index dc7b306..a413608 100644 --- a/src/shared/icons/flash-outline.tsx +++ b/src/shared/icons/flash-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const FlashOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/folder-outline.tsx b/src/shared/icons/folder-outline.tsx index 5981848..365a7ba 100644 --- a/src/shared/icons/folder-outline.tsx +++ b/src/shared/icons/folder-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const FolderOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/import-outline.tsx b/src/shared/icons/import-outline.tsx index e25b95f..1508c6a 100644 --- a/src/shared/icons/import-outline.tsx +++ b/src/shared/icons/import-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const ImportOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/lang.tsx b/src/shared/icons/lang.tsx index a2f7352..5f8a62d 100644 --- a/src/shared/icons/lang.tsx +++ b/src/shared/icons/lang.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const LangIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/logo.tsx b/src/shared/icons/logo.tsx index eaa00c3..36dcf2b 100644 --- a/src/shared/icons/logo.tsx +++ b/src/shared/icons/logo.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const LogoIcon = ({ className, diff --git a/src/shared/icons/message.tsx b/src/shared/icons/message.tsx index d3c4c14..0709b81 100644 --- a/src/shared/icons/message.tsx +++ b/src/shared/icons/message.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const MessageIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/paper-outline.tsx b/src/shared/icons/paper-outline.tsx index 597f6fc..fa05509 100644 --- a/src/shared/icons/paper-outline.tsx +++ b/src/shared/icons/paper-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const PaperOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/pause.tsx b/src/shared/icons/pause.tsx index 9b41184..23f6554 100644 --- a/src/shared/icons/pause.tsx +++ b/src/shared/icons/pause.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const PauseIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/play.tsx b/src/shared/icons/play.tsx index 10b2d5e..772ea7e 100644 --- a/src/shared/icons/play.tsx +++ b/src/shared/icons/play.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const PlayIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/plus.tsx b/src/shared/icons/plus.tsx index ed34f0d..95562a7 100644 --- a/src/shared/icons/plus.tsx +++ b/src/shared/icons/plus.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const PlusIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/reset.tsx b/src/shared/icons/reset.tsx index 454ee6a..15a7f20 100644 --- a/src/shared/icons/reset.tsx +++ b/src/shared/icons/reset.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const ResetIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/setting-outline.tsx b/src/shared/icons/setting-outline.tsx index 33bbd0c..4adf738 100644 --- a/src/shared/icons/setting-outline.tsx +++ b/src/shared/icons/setting-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const SettingsOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/stopwatch-outline.tsx b/src/shared/icons/stopwatch-outline.tsx index 528e75b..c57169b 100644 --- a/src/shared/icons/stopwatch-outline.tsx +++ b/src/shared/icons/stopwatch-outline.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const StopwatchOutlineIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/theme.tsx b/src/shared/icons/theme.tsx index f80b93b..d901e19 100644 --- a/src/shared/icons/theme.tsx +++ b/src/shared/icons/theme.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const ThemeIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/user.tsx b/src/shared/icons/user.tsx index 3aa39bd..cd8afc1 100644 --- a/src/shared/icons/user.tsx +++ b/src/shared/icons/user.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const UserIcon = ({ fill = 'currentColor', diff --git a/src/shared/icons/vees.tsx b/src/shared/icons/vees.tsx index 63f809d..75a52f8 100644 --- a/src/shared/icons/vees.tsx +++ b/src/shared/icons/vees.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Icon, IIcon } from '@/shared/ui'; +import { Icon } from '@/shared/ui'; +import type { IIcon } from '@/shared/ui'; export const VeesIcon = ({ fill = 'currentColor', diff --git a/src/shared/lib/date.ts b/src/shared/lib/date.ts new file mode 100644 index 0000000..a73e2cd --- /dev/null +++ b/src/shared/lib/date.ts @@ -0,0 +1,101 @@ +const daysOfWeek = [ + 'воскресенье', + 'понедельник', + 'вторник', + 'среда', + 'четверг', + 'пятница', + 'суббота', +]; + +const monthsOfYear = [ + 'январь', + 'февраль', + 'март', + 'апрель', + 'май', + 'июнь', + 'июль', + 'август', + 'сентябрь', + 'октябрь', + 'ноябрь', + 'декабрь', +]; + +export const getCurrentDateInfo = () => { + const now = new Date(); + + const dayOfWeek = daysOfWeek[now.getDay()]; + const monthNumber = String(now.getMonth() + 1).padStart(2, '0'); + const dayOfMonth = String(now.getDate()).padStart(2, '0'); + const year = now.getFullYear(); + + return { + dayOfMonth, + dayOfWeek, + monthNumber, + year, + }; +}; + +export const getDateInfo = (date: Date | string) => { + const parsedDate = typeof date === 'string' ? new Date(date) : date; + + if (isNaN(parsedDate.getTime())) { + throw new Error('Invalid date'); + } + + return { + day: parsedDate.getDate(), + dayOfWeek: daysOfWeek[parsedDate.getDay()], + hours: String(parsedDate.getHours()).padStart(2, '0'), + minutes: String(parsedDate.getMinutes()).padStart(2, '0'), + month: String(parsedDate.getMonth() + 1).padStart(2, '0'), + monthName: monthsOfYear[parsedDate.getMonth()], + year: parsedDate.getFullYear(), + }; +}; + +// Вспомогательная функция для склонения +const getDeclension = (number: number, forms: [string, string, string]): string => { + const mod10 = number % 10; + const mod100 = number % 100; + + if (mod100 >= 11 && mod100 <= 19) { + return forms[2]; + } + + if (mod10 === 1) { + return forms[0]; + } + + if (mod10 >= 2 && mod10 <= 4) { + return forms[1]; + } + + return forms[2]; +}; + +export const getDateRangeDuration = (startDate: Date | string, endDate: Date | string) => { + const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : startDate; + const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : endDate; + + if (isNaN(parsedStartDate.getTime()) || isNaN(parsedEndDate.getTime())) { + throw new Error('Invalid date'); + } + + const durationMs = parsedEndDate.getTime() - parsedStartDate.getTime(); + + if (durationMs < 0) { + throw new Error('End date must be greater than or equal to start date'); + } + + const hours = Math.floor(durationMs / (1000 * 60 * 60)) % 24; + const minutes = Math.floor(durationMs / (1000 * 60)) % 60; + + const hoursText = `${hours} ${getDeclension(hours, ['час', 'часа', 'часов'])}`; + const minutesText = `${minutes} ${getDeclension(minutes, ['минута', 'минуты', 'минут'])}`; + + return `${hoursText} ${minutesText}`.trim(); +}; diff --git a/src/shared/lib/utils.ts b/src/shared/lib/utils.ts deleted file mode 100644 index 7362243..0000000 --- a/src/shared/lib/utils.ts +++ /dev/null @@ -1,25 +0,0 @@ -export const getCurrentDateInfo = () => { - const daysOfWeek = [ - 'воскресенье', - 'понедельник', - 'вторник', - 'среда', - 'четверг', - 'пятница', - 'суббота', - ]; - - const now = new Date(); - - const dayOfWeek = daysOfWeek[now.getDay()]; // Название дня недели - const monthNumber = String(now.getMonth() + 1).padStart(2, '0'); // Номер месяца - const dayOfMonth = String(now.getDate()).padStart(2, '0'); // Номер дня в месяце - const year = now.getFullYear(); // Текущий год - - return { - dayOfMonth, - dayOfWeek, - monthNumber, - year, - }; -}; diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index a2b8e6c..e35b9dd 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -1,6 +1,5 @@ -import { JSX } from 'react'; - -import { AppRoutes } from '../constants'; +import type { AppRoutes } from '../constants'; +import type { JSX } from 'react'; export type * from './tailwind'; diff --git a/src/shared/ui/Background/Background.tsx b/src/shared/ui/Background/Background.tsx index a6b2d80..64767fa 100644 --- a/src/shared/ui/Background/Background.tsx +++ b/src/shared/ui/Background/Background.tsx @@ -1,6 +1,6 @@ import { clsx } from 'clsx'; -import { TComponent } from '@/shared/types'; +import type { TComponent } from '@/shared/types'; import styles from './background.module.scss'; diff --git a/src/shared/ui/Button/Button.tsx b/src/shared/ui/Button/Button.tsx index 218b655..44b5a74 100644 --- a/src/shared/ui/Button/Button.tsx +++ b/src/shared/ui/Button/Button.tsx @@ -1,7 +1,7 @@ import { clsx } from 'clsx'; import Link from 'next/link'; -import { AppRoutes } from '@/shared/constants'; +import type { AppRoutes } from '@/shared/constants'; import styles from './button.module.scss'; diff --git a/src/shared/ui/Chip/Chip.tsx b/src/shared/ui/Chip/Chip.tsx index 1a32bfd..48f6a2b 100644 --- a/src/shared/ui/Chip/Chip.tsx +++ b/src/shared/ui/Chip/Chip.tsx @@ -1,6 +1,6 @@ import { clsx } from 'clsx'; -import { TailwindColors } from '@/shared/types'; +import type { TailwindColors } from '@/shared/types'; import { Text } from '@/shared/ui'; import styles from './chip.module.scss'; @@ -8,14 +8,21 @@ import styles from './chip.module.scss'; interface IChip { children?: React.ReactNode className?: string + hidden?: boolean size?: 'small' | 'medium' } -export const Chip = ({ children, className, size = 'small' }: IChip) => ( - - {children} - -); +export const Chip = ({ children, className, hidden, size = 'small' }: IChip) => { + if (hidden) { + return null; + } + + return ( + + {children} + + ); +}; interface ICategory extends IChip { color?: TailwindColors diff --git a/src/shared/ui/Flex/Flex.tsx b/src/shared/ui/Flex/Flex.tsx index 6ef749c..5c7a23b 100644 --- a/src/shared/ui/Flex/Flex.tsx +++ b/src/shared/ui/Flex/Flex.tsx @@ -1,6 +1,6 @@ import { clsx } from 'clsx'; -import { TComponent } from '@/shared/types'; +import type { TComponent } from '@/shared/types'; import styles from './flex.module.scss'; diff --git a/src/shared/ui/Header/utils/CurrentDate.tsx b/src/shared/ui/Header/utils/CurrentDate.tsx index 78b1f45..310218d 100644 --- a/src/shared/ui/Header/utils/CurrentDate.tsx +++ b/src/shared/ui/Header/utils/CurrentDate.tsx @@ -1,6 +1,6 @@ 'use client'; -import { getCurrentDateInfo } from '@/shared/lib/utils'; +import { getCurrentDateInfo } from '@/shared/lib/date'; export const CurrentDate = () => { const { dayOfMonth, dayOfWeek, monthNumber } = getCurrentDateInfo(); diff --git a/src/shared/ui/Icon/Icon.tsx b/src/shared/ui/Icon/Icon.tsx index 11deb26..b55fd43 100644 --- a/src/shared/ui/Icon/Icon.tsx +++ b/src/shared/ui/Icon/Icon.tsx @@ -1,4 +1,6 @@ -import React, { ReactNode } from 'react'; +import React from 'react'; + +import type { ReactNode } from 'react'; export interface IIcon { children?: ReactNode diff --git a/src/shared/ui/Layout/Layout.tsx b/src/shared/ui/Layout/Layout.tsx index 739e371..52076ce 100644 --- a/src/shared/ui/Layout/Layout.tsx +++ b/src/shared/ui/Layout/Layout.tsx @@ -1,6 +1,6 @@ import { clsx } from 'clsx'; -import { TComponent } from '@/shared/types'; +import type { TComponent } from '@/shared/types'; import styles from './layout.module.scss'; diff --git a/src/shared/ui/List/ui/Horizontal/Horizontal.tsx b/src/shared/ui/List/ui/Horizontal/Horizontal.tsx index 76cf6f3..3492c81 100644 --- a/src/shared/ui/List/ui/Horizontal/Horizontal.tsx +++ b/src/shared/ui/List/ui/Horizontal/Horizontal.tsx @@ -4,7 +4,7 @@ import styles from './horizontal.module.scss'; export interface IListHorizontalItem { title: string - value: string + value: React.ReactNode } interface IListHorizontal { diff --git a/src/shared/ui/Loading/Loading.tsx b/src/shared/ui/Loading/Loading.tsx index 5ddcef6..840c43f 100644 --- a/src/shared/ui/Loading/Loading.tsx +++ b/src/shared/ui/Loading/Loading.tsx @@ -1,6 +1,6 @@ import { clsx } from 'clsx'; -import { TailwindColors } from '@/shared/types'; +import type { TailwindColors } from '@/shared/types'; import styles from './loading.module.scss'; diff --git a/src/shared/ui/Modal/ui/Base/Base.tsx b/src/shared/ui/Modal/ui/Base/Base.tsx index 844bbe6..5b5fcaf 100644 --- a/src/shared/ui/Modal/ui/Base/Base.tsx +++ b/src/shared/ui/Modal/ui/Base/Base.tsx @@ -1,9 +1,11 @@ import { Button, Flex, Text } from '@/shared/ui'; -import { IModal, Modal } from '../Modal/Modal'; +import { Modal } from '../Modal/Modal'; import styles from './base.module.scss'; +import type { IModal } from '../Modal/Modal'; + interface IModalBase extends IModal { iconAction?: React.ReactNode onClickAction?: () => void diff --git a/src/shared/ui/Section/Section.tsx b/src/shared/ui/Section/Section.tsx index f8b6eae..e842218 100644 --- a/src/shared/ui/Section/Section.tsx +++ b/src/shared/ui/Section/Section.tsx @@ -1,7 +1,7 @@ import { Fragment } from 'react'; import { ArrowDropdownIcon } from '@/shared/icons'; -import { TLinkOrClick } from '@/shared/types'; +import type { TLinkOrClick } from '@/shared/types'; import { Button, Divider, Flex, Text } from '@/shared/ui'; import { Background } from '../Background'; diff --git a/src/shared/ui/Text/Text.tsx b/src/shared/ui/Text/Text.tsx index 744dadf..278e7f5 100644 --- a/src/shared/ui/Text/Text.tsx +++ b/src/shared/ui/Text/Text.tsx @@ -1,6 +1,6 @@ import { clsx } from 'clsx'; -import { TailwindColors, TailwindSize, TailwindWeight, TComponent } from '@/shared/types'; +import type { TComponent, TailwindColors, TailwindSize, TailwindWeight } from '@/shared/types'; import styles from './text.module.scss'; diff --git a/src/widgets/AddExerciseModal/model/mock.ts b/src/widgets/AddExerciseModal/model/mock.ts index 9f40b4f..4e18f48 100644 --- a/src/widgets/AddExerciseModal/model/mock.ts +++ b/src/widgets/AddExerciseModal/model/mock.ts @@ -1,4 +1,4 @@ -import { IGroupExercises } from '../ui/AddExerciseModal'; +import type { IGroupExercises } from '../ui/AddExerciseModal'; export const mockAddExerciseModal: IGroupExercises[] = [ { diff --git a/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx b/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx index ba02288..e9df064 100644 --- a/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx +++ b/src/widgets/AddExerciseModal/ui/AddExerciseModal.tsx @@ -4,7 +4,7 @@ import { clsx } from 'clsx'; import { useState } from 'react'; import { AddOutlineIcon, SettingsOutlineIcon } from '@/shared/icons'; -import { Button, Flex, Text, Background, Input, ModalBase, Chip, Empty } from '@/shared/ui'; +import { Background, Button, Chip, Empty, Flex, Input, ModalBase, Text } from '@/shared/ui'; import { Image } from '@/shared/ui/client'; import styles from './addExerciseModal.module.scss'; diff --git a/src/widgets/Card/model/mock.ts b/src/widgets/Card/model/mock.ts index ea422ac..8a63ea7 100644 --- a/src/widgets/Card/model/mock.ts +++ b/src/widgets/Card/model/mock.ts @@ -1,5 +1,5 @@ -import { ICardExerciseItem } from '../ui/ExerciseItem/ExerciseItem'; -import { ICardVeesItem } from '../ui/VeesItem/VeesItem'; +import type { ICardExerciseItem } from '../ui/ExerciseItem/ExerciseItem'; +import type { ICardVeesItem } from '../ui/VeesItem/VeesItem'; export const mockVeesListItems: ICardVeesItem[] = [ { @@ -38,35 +38,36 @@ export const mockVeesListItems: ICardVeesItem[] = [ export const mockExerciseListItems: ICardExerciseItem[] = [ { - comment: 'Это некая заметка к упражнению на будущее, а может просто по приколу. Я не знаю', - groupColor: '#FAC938', - groupName: 'Спина', - name: 'Горизонтальная тяга', - previousResult: [ - { count: 10, weight: 30 }, - { count: 7, weight: 30 }, - { count: 10, weight: 28 }, - ], - result: [ - { count: 10, weight: 30 }, - { count: 6, weight: 32 }, - { count: 11, weight: 25 }, - ], + approachCount: 21, + commentCount: 3, + duration: { + from: '2024-11-12T17:06:00', + to: '2024-11-12T19:04:00', + }, + exerciseCount: 7, + number: 98, + resultDownCount: 1, + resultUpCount: 4, + veesTemplate: { + color: '#FA4838', + isEdited: true, + name: 'Вторник', + number: 8, + }, }, { - groupColor: '#FA4838', - groupName: 'Средние дельты', - name: 'Разведения в кроссовере', - previousName: 'Жим гантелей', - previousResult: [{ count: 14, weight: 20 }], - result: [{ count: 12, weight: 20 }], - }, - { - groupColor: '#1A80E5', - groupName: 'Грудь', - name: 'Жим лежа на наклонной скамье', - previousName: 'Жим гантелей', - previousResult: [{ count: 6, weight: 80 }, { count: 4, weight: 80 }], - result: [{ count: 6, weight: 80 }, { count: 2, weight: 90 }], + approachCount: 16, + duration: { + from: '2024-11-10T13:35:00', + to: '2024-11-10T16:01:00', + }, + exerciseCount: 5, + number: 97, + resultUpCount: 2, + veesTemplate: { + color: '#FA4838', + name: 'Вторник', + number: 7, + }, }, ]; diff --git a/src/widgets/Card/ui/Card/Card.tsx b/src/widgets/Card/ui/Card/Card.tsx index b5f1fd7..28dfe60 100644 --- a/src/widgets/Card/ui/Card/Card.tsx +++ b/src/widgets/Card/ui/Card/Card.tsx @@ -1,11 +1,12 @@ import { clsx } from 'clsx'; -import { Dispatch, SetStateAction } from 'react'; import { ArrowDropdownIcon } from '@/shared/icons'; import { Background, Button, Flex } from '@/shared/ui'; import styles from './card.module.scss'; +import type { Dispatch, SetStateAction } from 'react'; + interface ICard { children: React.ReactNode chipList?: React.ReactNode @@ -22,7 +23,9 @@ export const Card = ({ setIsOpen, }: ICard) => ( - {leftAction} + + {leftAction} + {chipList} diff --git a/src/widgets/Card/ui/Card/card.module.scss b/src/widgets/Card/ui/Card/card.module.scss index ab162bc..947f82c 100644 --- a/src/widgets/Card/ui/Card/card.module.scss +++ b/src/widgets/Card/ui/Card/card.module.scss @@ -13,6 +13,10 @@ padding: 15px 10px 15px 0; } +.leftAction { + min-width: 48px; +} + .chipList { position: absolute; top: -12px; diff --git a/src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx b/src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx index 3b56a0c..d34b1a2 100644 --- a/src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx +++ b/src/widgets/Card/ui/ExerciseItem/ExerciseItem.tsx @@ -1,27 +1,38 @@ 'use client'; +import { clsx } from 'clsx'; import { useState } from 'react'; -import { MessageIcon } from '@/shared/icons'; -import { Chip, Text } from '@/shared/ui'; +import { + ArrowDropdownIcon, + MessageIcon, + PaperOutlineIcon, + StopwatchOutlineIcon, +} from '@/shared/icons'; +import { getDateInfo, getDateRangeDuration } from '@/shared/lib/date'; +import { Chip, Flex, List, Text } from '@/shared/ui'; import { Card } from '../Card/Card'; import styles from './exerciseItem.module.scss'; -interface IVeesRecord { - count: number - weight: number -} - export interface ICardExerciseItem { - comment?: string - groupColor?: string - groupName?: string - name: string - previousName?: string - previousResult?: IVeesRecord[] - result?: IVeesRecord[] + approachCount?: number + commentCount?: number + duration: { + from: string + to: string + } + exerciseCount?: number + number: number + resultDownCount?: number + resultUpCount?: number + veesTemplate?: { + name: string + color: string + number: number + isEdited?: boolean + } } interface IExerciseItem { @@ -32,31 +43,96 @@ export const ExerciseItem = ({ item }: IExerciseItem) => { const [isOpen, setIsOpen] = useState(null); const { - comment, + approachCount = 0, + commentCount, + duration, + exerciseCount, + number, + resultDownCount, + resultUpCount, + veesTemplate, } = item; + const { hours: hoursFrom, minutes: minutesFrom } = getDateInfo(duration.from); + const { + day, + hours: hoursTo, + minutes: minutesTo, + monthName, + year, + } = getDateInfo(duration.to); + const rangeDuration = getDateRangeDuration(duration.from, duration.to); + return ( - 12 ноября 2024 - {comment ? ( + + + {`${day} ${monthName} ${year}`} + + + + {commentCount ? ( - 3 + {commentCount} ) : null} )} isOpen={isOpen} - leftAction={( - - )} + leftAction={{`${number}.`}} setIsOpen={setIsOpen} > - HI +
+ } + title="Тренировка" + value={( + + )} + /> + } + title="Длительность" + value={rangeDuration} + /> + +
); }; diff --git a/src/widgets/Card/ui/ExerciseItem/exerciseItem.module.scss b/src/widgets/Card/ui/ExerciseItem/exerciseItem.module.scss index e69de29..76f7b61 100644 --- a/src/widgets/Card/ui/ExerciseItem/exerciseItem.module.scss +++ b/src/widgets/Card/ui/ExerciseItem/exerciseItem.module.scss @@ -0,0 +1,12 @@ +.container { + height: 58px; + max-height: fit-content; + + overflow: clip; + + transition: all 0.15s linear; +} + +.open { + height: 210px; +} \ No newline at end of file diff --git a/src/widgets/Card/ui/ExerciseList/ExerciseList.tsx b/src/widgets/Card/ui/ExerciseList/ExerciseList.tsx index 29e0744..521d7ff 100644 --- a/src/widgets/Card/ui/ExerciseList/ExerciseList.tsx +++ b/src/widgets/Card/ui/ExerciseList/ExerciseList.tsx @@ -1,6 +1,8 @@ import { Flex } from '@/shared/ui'; -import { ICardExerciseItem, ExerciseItem } from '../ExerciseItem/ExerciseItem'; +import { ExerciseItem } from '../ExerciseItem/ExerciseItem'; + +import type { ICardExerciseItem } from '../ExerciseItem/ExerciseItem'; interface IExerciseList { items: ICardExerciseItem[] @@ -9,7 +11,8 @@ interface IExerciseList { export const ExerciseList = ({ items }: IExerciseList) => ( {items.map((item, index) => ( - + // TODO: add id key={`${index}${item.id}`} + ))} ); diff --git a/src/widgets/Card/ui/VeesItem/veesItem.module.scss b/src/widgets/Card/ui/VeesItem/veesItem.module.scss index 830bceb..34841b6 100644 --- a/src/widgets/Card/ui/VeesItem/veesItem.module.scss +++ b/src/widgets/Card/ui/VeesItem/veesItem.module.scss @@ -39,7 +39,12 @@ } .drag { - padding: 0 10px 0 12px; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + padding-left: 4px; color: theme('colors.base.800'); cursor: grab; diff --git a/src/widgets/Card/ui/VeesList/VeesList.tsx b/src/widgets/Card/ui/VeesList/VeesList.tsx index 6ef5cdd..c0d7936 100644 --- a/src/widgets/Card/ui/VeesList/VeesList.tsx +++ b/src/widgets/Card/ui/VeesList/VeesList.tsx @@ -1,10 +1,12 @@ import { FinishOutlineIcon } from '@/shared/icons'; import { Button, Flex } from '@/shared/ui'; -import { ICardVeesItem, VeesItem } from '../VeesItem/VeesItem'; +import { VeesItem } from '../VeesItem/VeesItem'; import styles from './veesList.module.scss'; +import type { ICardVeesItem } from '../VeesItem/VeesItem'; + interface IVeesList { items: ICardVeesItem[] } diff --git a/src/widgets/Navbar/ui/Navbar/Navbar.tsx b/src/widgets/Navbar/ui/Navbar/Navbar.tsx index fc6694a..3d46431 100644 --- a/src/widgets/Navbar/ui/Navbar/Navbar.tsx +++ b/src/widgets/Navbar/ui/Navbar/Navbar.tsx @@ -5,7 +5,7 @@ import { usePathname } from 'next/navigation'; import { AppRoutes } from '@/shared/constants'; import { AddOutlineIcon, SettingsOutlineIcon, VeesIcon } from '@/shared/icons'; -import { TLinkOrClick } from '@/shared/types'; +import type { TLinkOrClick } from '@/shared/types'; import { Background, Button, Flex, Layout } from '@/shared/ui'; import { BackActiveVees } from '../BackActiveVees/BackActiveVees'; From 842266a134cc3c97cd1aa5f97eee68ba60cdd537 Mon Sep 17 00:00:00 2001 From: Mark Melior Date: Wed, 8 Jan 2025 10:54:18 +0300 Subject: [PATCH 3/3] VEES-18 | Rename monthsOfYear --- src/shared/lib/date.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shared/lib/date.ts b/src/shared/lib/date.ts index a73e2cd..09a5827 100644 --- a/src/shared/lib/date.ts +++ b/src/shared/lib/date.ts @@ -9,18 +9,18 @@ const daysOfWeek = [ ]; const monthsOfYear = [ - 'январь', - 'февраль', - 'март', - 'апрель', - 'май', - 'июнь', - 'июль', - 'август', - 'сентябрь', - 'октябрь', - 'ноябрь', - 'декабрь', + 'января', + 'февраля', + 'марта', + 'апреля', + 'мая', + 'июня', + 'июля', + 'августа', + 'сентября', + 'октября', + 'ноября', + 'декабря', ]; export const getCurrentDateInfo = () => {