feat: swiper for boards on desktop

This commit is contained in:
2025-08-16 19:57:22 +04:00
parent a4bcd62189
commit 2e9ed02722
5 changed files with 116 additions and 68 deletions

View File

@ -1,7 +1,7 @@
"use client";
import React from "react";
import { Group, ScrollArea } from "@mantine/core";
import { Group } from "@mantine/core";
import Board from "@/app/deals/components/desktop/Board/Board";
import CreateBoardButton from "@/app/deals/components/desktop/CreateBoardButton/CreateBoardButton";
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
@ -24,15 +24,11 @@ const Boards = () => {
};
return (
<ScrollArea
offsetScrollbars={"x"}
scrollbars={"x"}
scrollbarSize={0}
w={"100%"}>
<Group
pr={"xs"}
wrap={"nowrap"}
gap={0}>
gap={"md"}
pr={"sm"}
style={{ maxWidth: "100%", overflow: "hidden" }}>
<SortableDnd
initialItems={boards}
renderItem={renderBoard}
@ -41,14 +37,15 @@ const Boards = () => {
containerStyle={{
flexWrap: "nowrap",
gap: "var(--mantine-spacing-md)",
margin: "var(--mantine-spacing-md)",
paddingBlock: "var(--mantine-spacing-md)",
paddingLeft: "var(--mantine-spacing-md)",
}}
dragHandleStyle={{ cursor: "pointer" }}
disabled={isMobile}
swiperEnabled
/>
<CreateBoardButton />
</Group>
</ScrollArea>
);
};

View File

@ -28,6 +28,7 @@ const Header = () => {
wrap={"nowrap"}
pr={"md"}>
<Boards />
<Group wrap={"nowrap"}>
<ColorSchemeToggle />
<ProjectSelect
data={projects}
@ -35,6 +36,7 @@ const Header = () => {
onChange={value => value && setSelectedProject(value)}
/>
</Group>
</Group>
);
};

View File

@ -13,7 +13,7 @@
}
}
.swiperContainer :global(.swiper-scrollbar-drag) {
.swiper-container :global(.swiper-scrollbar-drag) {
@mixin dark {
background-color: var(--mantine-color-dark-9);
}
@ -22,6 +22,6 @@
}
}
.swiperContainer :global(.swiper-slide) {
.swiper-container :global(.swiper-slide) {
padding-bottom: 20px;
}

View File

@ -101,7 +101,7 @@ const FunnelDnd = <
return (
<Swiper
ref={swiperRef}
className={classes.swiperContainer}
className={classes["swiper-container"]}
slidesPerView={1.2}
modules={[Pagination]}
freeMode={{ enabled: false }}
@ -118,7 +118,7 @@ const FunnelDnd = <
return (
<Swiper
ref={swiperRef}
className={classes.swiperContainer}
className={classes["swiper-container"]}
modules={[Scrollbar, Mousewheel, FreeMode]}
spaceBetween={15}
slidesPerView={"auto"}

View File

@ -11,6 +11,8 @@ import { Active, DndContext, DragEndEvent } from "@dnd-kit/core";
import { restrictToHorizontalAxis } from "@dnd-kit/modifiers";
import { SortableContext } from "@dnd-kit/sortable";
import { LexoRank } from "lexorank";
import { FreeMode, Mousewheel, Scrollbar } from "swiper/modules";
import { Swiper, SwiperSlide } from "swiper/react";
import { Box, Flex } from "@mantine/core";
import useDndSensors from "@/app/deals/hooks/useSensors";
import { SortableOverlay } from "@/components/dnd/SortableDnd/SortableOverlay";
@ -35,6 +37,7 @@ type Props<T extends BaseItem> = {
containerStyle?: CSSProperties;
vertical?: boolean;
disabled?: boolean;
swiperEnabled?: boolean;
};
const SortableDnd = <T extends BaseItem>({
@ -45,8 +48,9 @@ const SortableDnd = <T extends BaseItem>({
onDragEnd,
onItemClick,
containerStyle,
vertical,
vertical = false,
disabled = false,
swiperEnabled = false,
}: Props<T>) => {
const [active, setActive] = useState<Active | null>(null);
const [items, setItems] = useState<T[]>([]);
@ -98,16 +102,48 @@ const SortableDnd = <T extends BaseItem>({
setActive(null);
};
return (
<DndContext
modifiers={[restrictToHorizontalAxis]}
sensors={sensors}
onDragStart={({ active }) => setActive(active)}
onDragEnd={onDragEndLocal}
onDragCancel={() => setActive(null)}>
<SortableContext
items={items}
disabled={disabled}>
const renderWithSwiper = () => (
<Swiper
modules={[Scrollbar, Mousewheel, FreeMode]}
spaceBetween={15}
slidesPerView={"auto"}
scrollbar={{ hide: false }}
mousewheel={{
enabled: true,
sensitivity: 0.2,
}}
style={containerStyle}
direction={vertical ? "vertical" : "horizontal"}
freeMode={{ enabled: true }}
grabCursor>
{items.map((item, index) => (
<SwiperSlide
style={{ width: "fit-content" }}
key={index}
onClick={e => {
if (!onItemClick) return;
e.stopPropagation();
onItemClick(item);
}}>
<SortableItem
id={item.id}
disabled={disabled}
renderItem={renderDraggable =>
renderItem(item, renderDraggable)
}
renderDraggable={
renderDraggable
? () => renderDraggable(item)
: undefined
}
dragHandleStyle={dragHandleStyle}
/>
</SwiperSlide>
))}
</Swiper>
);
const renderWithFlex = () => (
<Flex
style={{
gap: 0,
@ -139,6 +175,19 @@ const SortableDnd = <T extends BaseItem>({
</Box>
))}
</Flex>
);
return (
<DndContext
modifiers={[restrictToHorizontalAxis]}
sensors={sensors}
onDragStart={({ active }) => setActive(active)}
onDragEnd={onDragEndLocal}
onDragCancel={() => setActive(null)}>
<SortableContext
items={items}
disabled={disabled}>
{swiperEnabled ? renderWithSwiper() : renderWithFlex()}
</SortableContext>
<SortableOverlay>
{activeItem ? renderItem(activeItem, renderDraggable) : null}