refactor: removed constant sizes

This commit is contained in:
2025-08-14 12:15:09 +04:00
parent b6cec9a308
commit 255a39e2bb
14 changed files with 109 additions and 121 deletions

View File

@ -1,6 +1,6 @@
.create-button { .create-button {
padding: 11px 10px 12px 10px; padding: 10px 10px 11px 10px;
border-bottom: 2px solid gray; border-bottom: 2px solid gray;
} }

View File

@ -16,7 +16,7 @@ const CreateBoardButtonMobile = () => {
<Box <Box
onClick={startEditing} onClick={startEditing}
className={styles["create-button"]}> className={styles["create-button"]}>
<IconPlus size={22} /> <IconPlus />
</Box> </Box>
)} )}
modalTitle={"Создание доски"} modalTitle={"Создание доски"}

View File

@ -8,15 +8,9 @@ type Props = {
board: BoardSchema; board: BoardSchema;
startEditing: () => void; startEditing: () => void;
isHovered?: boolean; isHovered?: boolean;
menuIconSize?: number;
}; };
const BoardMenu: FC<Props> = ({ const BoardMenu: FC<Props> = ({ board, startEditing, isHovered = true }) => {
board,
startEditing,
isHovered = true,
menuIconSize = 16,
}) => {
const { selectedBoard, onDeleteBoard } = useBoardsContext(); const { selectedBoard, onDeleteBoard } = useBoardsContext();
return ( return (
@ -29,7 +23,7 @@ const BoardMenu: FC<Props> = ({
cursor: "pointer", cursor: "pointer",
}} }}
onClick={e => e.stopPropagation()}> onClick={e => e.stopPropagation()}>
<IconDotsVertical size={menuIconSize} /> <IconDotsVertical />
</Box> </Box>
</Menu.Target> </Menu.Target>
<Menu.Dropdown> <Menu.Dropdown>

View File

@ -1,26 +1,31 @@
import React from "react"; import React from "react";
import { IconPlus } from "@tabler/icons-react"; import { IconPlus } from "@tabler/icons-react";
import { Box, Center, Stack } from "@mantine/core"; import { Box, Center, Group, Stack, Text } from "@mantine/core";
import { useStatusesContext } from "@/app/deals/contexts/StatusesContext"; import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
import InPlaceInput from "@/components/ui/InPlaceInput/InPlaceInput"; import InPlaceInput from "@/components/ui/InPlaceInput/InPlaceInput";
import useIsMobile from "@/hooks/useIsMobile";
import styles from "./CreateStatusButton.module.css"; import styles from "./CreateStatusButton.module.css";
const CreateStatusButton = () => { const CreateStatusButton = () => {
const { onCreateStatus } = useStatusesContext(); const { onCreateStatus } = useStatusesContext();
const isMobile = useIsMobile();
return ( return (
<Stack> <Stack>
<Box <Box className={styles.container}>
ml={6}
className={styles.container}>
<InPlaceInput <InPlaceInput
placeholder={"Название колонки"} placeholder={"Название колонки"}
onComplete={onCreateStatus} onComplete={onCreateStatus}
getChildren={startEditing => ( getChildren={startEditing => (
<Center <Center
p={15} p={"sm"}
onClick={() => startEditing()}> onClick={() => startEditing()}>
<IconPlus size={20} /> <Group gap={"xs"} wrap={"nowrap"} align={"start"}>
<IconPlus />
{isMobile && (
<Text>Добавить</Text>
)}
</Group>
</Center> </Center>
)} )}
modalTitle={"Создание колонки"} modalTitle={"Создание колонки"}

View File

@ -27,54 +27,46 @@ const Funnel: FC = () => {
} = useDealsAndStatusesDnd(); } = useDealsAndStatusesDnd();
const renderFunnelDnd = () => ( const renderFunnelDnd = () => (
<> <FunnelDnd
<FunnelDnd containers={sortedStatuses}
containers={sortedStatuses} items={deals}
items={deals} onDragStart={handleDragStart}
onDragStart={handleDragStart} onDragOver={handleDragOver}
onDragOver={handleDragOver} onDragEnd={handleDragEnd}
onDragEnd={handleDragEnd} getContainerId={(status: StatusSchema) => `${status.id}-status`}
getContainerId={(status: StatusSchema) => `${status.id}-status`} getItemsByContainer={(status: StatusSchema, items: DealSchema[]) =>
getItemsByContainer={( sortByLexorank(
status: StatusSchema, items.filter(deal => deal.statusId === status.id)
items: DealSchema[] )
) => }
sortByLexorank( renderContainer={(
items.filter(deal => deal.statusId === status.id) status: StatusSchema,
) funnelColumnComponent: ReactNode
} ) => (
renderContainer={( <StatusColumnWrapper
status: StatusSchema, status={status}
funnelColumnComponent: ReactNode isDragging={activeStatus?.id === status.id}>
) => ( {funnelColumnComponent}
<StatusColumnWrapper </StatusColumnWrapper>
status={status} )}
isDragging={activeStatus?.id === status.id}> renderItem={(deal: DealSchema) => (
{funnelColumnComponent} <DealContainer
</StatusColumnWrapper> key={deal.id}
)} deal={deal}
renderItem={(deal: DealSchema) => ( />
<DealContainer )}
key={deal.id} activeContainer={activeStatus}
deal={deal} activeItem={activeDeal}
/> renderItemOverlay={(deal: DealSchema) => <DealCard deal={deal} />}
)} renderContainerOverlay={(status: StatusSchema, children) => (
activeContainer={activeStatus} <StatusColumnWrapper
activeItem={activeDeal} status={status}
renderItemOverlay={(deal: DealSchema) => ( isDragging>
<DealCard deal={deal} /> {children}
)} </StatusColumnWrapper>
renderContainerOverlay={(status: StatusSchema, children) => ( )}
<StatusColumnWrapper disabledColumns={isMobile}
status={status} />
isDragging>
{children}
</StatusColumnWrapper>
)}
disabledColumns={isMobile}
/>
{!isMobile && <CreateStatusButton />}
</>
); );
if (isMobile) return renderFunnelDnd(); if (isMobile) return renderFunnelDnd();
@ -86,8 +78,9 @@ const Funnel: FC = () => {
<Group <Group
align={"start"} align={"start"}
wrap={"nowrap"} wrap={"nowrap"}
gap={0}> gap={"xs"}>
{renderFunnelDnd()} {renderFunnelDnd()}
<CreateStatusButton />
</Group> </Group>
</ScrollArea> </ScrollArea>
); );

View File

@ -7,3 +7,7 @@
width: 80vw; width: 80vw;
} }
} }
.header {
border-bottom: solid blue 3px;
}

View File

@ -27,12 +27,13 @@ const StatusColumnWrapper = ({
}; };
return ( return (
<Box <Box className={styles.container}>
mx={7}
className={styles.container}>
<Group <Group
justify={"space-between"} justify={"space-between"}
className={"flex-nowrap border-b-3 border-blue-500 mb-3 p-3"}> p={"sm"}
wrap={"nowrap"}
mb={"xs"}
className={styles.header}>
<InPlaceInput <InPlaceInput
defaultValue={status.name} defaultValue={status.name}
onComplete={value => handleSave(value)} onComplete={value => handleSave(value)}

View File

@ -23,12 +23,11 @@ const StatusMenu: FC<Props> = ({ status, handleEdit }) => {
<Menu> <Menu>
<Menu.Target> <Menu.Target>
<Box <Box
p={5}
style={{ style={{
cursor: "pointer", cursor: "pointer",
}} }}
onClick={e => e.stopPropagation()}> onClick={e => e.stopPropagation()}>
<IconDotsVertical size={16} /> <IconDotsVertical />
</Box> </Box>
</Menu.Target> </Menu.Target>
<Menu.Dropdown> <Menu.Dropdown>

View File

@ -22,7 +22,7 @@ const BoardStatusesEditorDrawer: FC = () => {
const renderDraggable = () => ( const renderDraggable = () => (
<Box p={"xs"}> <Box p={"xs"}>
<IconGripVertical size={22} /> <IconGripVertical />
</Box> </Box>
); );

View File

@ -37,7 +37,6 @@ const StatusMobile: FC<Props> = ({ status }) => {
<BoardMenu <BoardMenu
board={status} board={status}
startEditing={startEditing} startEditing={startEditing}
menuIconSize={22}
/> />
</Group> </Group>
); );

View File

@ -22,7 +22,7 @@ const ProjectBoardsEditorDrawer: FC = () => {
const renderDraggable = () => ( const renderDraggable = () => (
<Box p={"xs"}> <Box p={"xs"}>
<IconGripVertical size={22} /> <IconGripVertical />
</Box> </Box>
); );

View File

@ -8,14 +8,9 @@ import styles from "./../ProjectsEditorDrawer.module.css";
type Props = { type Props = {
project: ProjectSchema; project: ProjectSchema;
startEditing: () => void; startEditing: () => void;
menuIconSize: number;
}; };
const ProjectMenu: FC<Props> = ({ const ProjectMenu: FC<Props> = ({ project, startEditing }) => {
project,
startEditing,
menuIconSize = 16,
}) => {
const { onDeleteProject } = useProjectsContext(); const { onDeleteProject } = useProjectsContext();
return ( return (
@ -24,7 +19,7 @@ const ProjectMenu: FC<Props> = ({
<Box <Box
className={styles["menu-button"]} className={styles["menu-button"]}
onClick={e => e.stopPropagation()}> onClick={e => e.stopPropagation()}>
<IconDotsVertical size={menuIconSize} /> <IconDotsVertical />
</Box> </Box>
</Menu.Target> </Menu.Target>
<Menu.Dropdown> <Menu.Dropdown>

View File

@ -46,7 +46,6 @@ const ProjectMobile: FC<Props> = ({ project }) => {
<ProjectMenu <ProjectMenu
project={project} project={project}
startEditing={startEditing} startEditing={startEditing}
menuIconSize={22}
/> />
</Group> </Group>
); );

View File

@ -69,7 +69,7 @@ const FunnelDnd = <
containers.map(container => { containers.map(container => {
const containerItems = getItemsByContainer(container, items); const containerItems = getItemsByContainer(container, items);
const containerId = getContainerId(container); const containerId = getContainerId(container);
return ( const item = (
<SortableItem <SortableItem
key={containerId} key={containerId}
id={containerId} id={containerId}
@ -86,11 +86,13 @@ const FunnelDnd = <
} }
/> />
); );
if (!isMobile) return item;
return <Carousel.Slide key={containerId}>{item}</Carousel.Slide>;
}); });
const renderBody = () => ( const renderBody = () => {
<> if (isMobile) {
{isMobile ? ( return (
<Carousel <Carousel
slideSize={"80%"} slideSize={"80%"}
slideGap={"md"} slideGap={"md"}
@ -101,31 +103,17 @@ const FunnelDnd = <
{renderContainers()} {renderContainers()}
<CreateStatusButton /> <CreateStatusButton />
</Carousel> </Carousel>
) : ( );
renderContainers() }
)} return (
<FunnelOverlay <Group
activeContainer={activeContainer} gap={"xs"}
activeItem={activeItem} wrap="nowrap"
renderContainer={container => { align="start">
const containerItems = getItemsByContainer( {renderContainers()}
container, </Group>
items );
); };
const containerId = getContainerId(container);
return renderContainerOverlay(
container,
<FunnelColumn
id={containerId}
items={containerItems}
renderItem={renderItem}
/>
);
}}
renderItem={renderItemOverlay}
/>
</>
);
return ( return (
<DndContext <DndContext
@ -137,16 +125,27 @@ const FunnelDnd = <
<SortableContext <SortableContext
items={containers.map(getContainerId)} items={containers.map(getContainerId)}
strategy={horizontalListSortingStrategy}> strategy={horizontalListSortingStrategy}>
{isMobile ? ( {renderBody()}
renderBody() <FunnelOverlay
) : ( activeContainer={activeContainer}
<Group activeItem={activeItem}
gap={0} renderContainer={container => {
wrap="nowrap" const containerItems = getItemsByContainer(
align="start"> container,
{renderBody()} items
</Group> );
)} const containerId = getContainerId(container);
return renderContainerOverlay(
container,
<FunnelColumn
id={containerId}
items={containerItems}
renderItem={renderItem}
/>
);
}}
renderItem={renderItemOverlay}
/>
</SortableContext> </SortableContext>
</DndContext> </DndContext>
); );