Skip to content

Commit

Permalink
Drag-n-drop для колонок
Browse files Browse the repository at this point in the history
  • Loading branch information
DeDxYk594 committed Dec 1, 2024
1 parent 707ffee commit 24313fd
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 85 deletions.
1 change: 1 addition & 0 deletions src/api/boards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const getBoardContent = async (
columnIndex.set(column.id, idx);
return {
...column,
isStub: false,
cards: [], // инициализация пустым массивом для типа BoardColumn
};
}
Expand Down
1 change: 1 addition & 0 deletions src/api/mocks/activeBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const activeBoardMock: ActiveBoard = {
columns: [
{
id: 1,
isStub: false,
title: 'Задачи',
cards: [
{
Expand Down
2 changes: 1 addition & 1 deletion src/api/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export const loginUser = async (
return true;
case HTTP_STATUS_UNAUTHORIZED:
showToast('Неверные учётные данные', 'error');
throw new Error('Неверные учетные данные');
return false;
default:
showToast('Неизвестная ошибка', 'error');
throw new Error('Беды на бэке');
Expand Down
9 changes: 7 additions & 2 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ComponentProps } from '@/jsxCore/types';
import './button.scss'
import './button.scss';
interface ButtonProps extends ComponentProps {
text?: string;
icon?: string;
callback?: (event: PointerEvent) => void;
variant?: 'default' | 'negative' | 'positive' | 'accent' | 'transparent';
extraRounded?: boolean;
fullWidth?: true; // Флаг; указывает, должна ли кнопка принимать ширину родителя
}

Expand All @@ -17,7 +18,11 @@ export const Button = (props: ButtonProps) => {
return (
<div>
<div
className={['button', `button__${props.variant ?? 'default'}`]}
className={[
'button',
`button__${props.variant ?? 'default'}`,
props.extraRounded && 'button__extra-rounded',
]}
style={props.fullWidth === true ? 'width: 100%' : ''}
ON_click={props.callback}
>
Expand Down
44 changes: 41 additions & 3 deletions src/components/KanbanColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,24 @@ import { useEffectRefs, useState } from '@/jsxCore/hooks';
import { Input } from './Input';
import './kanbanColumn.scss';
import { KanbanCard } from './KanbanCard';
import { colHeaderHeights } from '@/stores/dndStore';
import { colHeaderHeights, setDndStore, useDndStore } from '@/stores/dndStore';

interface KanbanColumnProps extends ComponentProps {
columnIndex: number;
columnId: number;
}

const DND_THRESHOLD = 10;

export const KanbanColumn = (props: KanbanColumnProps) => {
const [isInputOpened, setIsInputOpened] = useState(false);
const [newCardText, setNewCardText] = useState('');
const activeBoard = useActiveBoardStore() as ActiveBoard;
const columnData = activeBoard.columns[props.columnIndex];
const [dragStart, setDragStart] = useState<
[x: number, y: number] | undefined
>(undefined);
const [dragOffset, setDragOffset] = useState<[x: number, y: number]>([0, 0]);

const submitCreateCard = (newText: string) => {
if (newText.length < 3) {
Expand All @@ -44,7 +51,38 @@ export const KanbanColumn = (props: KanbanColumnProps) => {
}, 200);
});
return (
<div class="kanban-column">
<div
class="kanban-column"
ON_mousedown={(ev: PointerEvent) => {
setDragStart([ev.x, ev.y]);
setDragOffset([ev.offsetX, ev.offsetY]);
}}
ON_mousemove={(ev: PointerEvent) => {
if (dragStart !== undefined) {
if (
Math.sqrt(
Math.pow(dragStart[0] - ev.x, 2) +
Math.pow(dragStart[1] - ev.y, 2)
) > DND_THRESHOLD
) {
const dndStore = useDndStore();
if (dndStore === undefined) {
setDndStore({
type: 'column',
activeColumnIdx: props.columnIndex,
offset: dragOffset,
activeColumn: activeBoard.columns[props.columnIndex],
});
console.log('offset', dragOffset);
setDragStart(undefined);
}
}
}
}}
ON_mouseleave={() => {
setDragStart(undefined);
}}
>
<div class="kanban-column__header" ref="header">
<EditableText
readOnly={activeBoard.myRole === 'viewer'}
Expand Down Expand Up @@ -122,10 +160,10 @@ export const KanbanColumn = (props: KanbanColumnProps) => {
setIsInputOpened(true);
}}
fullWidth
extraRounded
/>
)}

<div style="height: 1px" />
{activeBoard?.myRole !== 'viewer' && isInputOpened && (
<div>
<Input
Expand Down
3 changes: 3 additions & 0 deletions src/components/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
user-select: none;
transition: background-color 0.3s ease, opacity 0.3s ease;
}
.button__extra-rounded {
border-radius: 8px;
}
.button:hover {
opacity: 0.9;
}
Expand Down
16 changes: 9 additions & 7 deletions src/components/kanbanColumn.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
}
}
.kanban-column__header {
padding-top: 5px;
padding-top: 8px;
display: flex;
align-items: center;
position: relative;
}
.kanban-column__title {
user-select: none;
font-size: 1rem;
font-weight: 500;
padding-left: 10px;
Expand All @@ -40,15 +41,16 @@
color: red;
}
.kanban-column__button {
transition: 0.3s ease;
color: rgba(0, 0, 0, 0);
cursor: pointer;
position: absolute;
top: 6px;
width: 24px;
height: 24px;
border-radius: 3px;
padding-left: 4px;
padding-top: 2px;
top: 8px;
width: 32px;
height: 32px;
border-radius: 8px;
padding-left: 8px;
padding-top: 7px;
}
@media screen and (max-width: 800px) {
.kanban-column__button {
Expand Down
Loading

0 comments on commit 24313fd

Please sign in to comment.