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 {
padding: 11px 10px 12px 10px;
padding: 10px 10px 11px 10px;
border-bottom: 2px solid gray;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,12 +27,13 @@ const StatusColumnWrapper = ({
};
return (
<Box
mx={7}
className={styles.container}>
<Box className={styles.container}>
<Group
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
defaultValue={status.name}
onComplete={value => handleSave(value)}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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