Skip to content

Commit

Permalink
[FEAT] 픽 렌더링 카드에서 리스트 아이템으로 교체 (#501)
Browse files Browse the repository at this point in the history
* feat: PickRenderModeState 구현

* feat: PickRecordListLayout 컴포넌트 구현

* feat: PickCard대신 PickRecord 렌더링으로 변경

* feat: usePickRenderModeStore 의존성 제거
  • Loading branch information
dmdgpdi authored Nov 19, 2024
1 parent 8108af3 commit c6e5ae2
Show file tree
Hide file tree
Showing 15 changed files with 226 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default function UnclassifiedFolderPage() {
<DraggablePickListViewer
pickList={getOrderedPickListByFolderId(basicFolderMap['UNCLASSIFIED'].id)}
folderId={basicFolderMap['UNCLASSIFIED'].id}
viewType="list"
/>
);
}
12 changes: 11 additions & 1 deletion frontend/techpick/src/components/DragOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import { useEffect, useState } from 'react';
import type { CSSProperties } from 'react';
import { DragOverlay as DndKitDragOverlay } from '@dnd-kit/core';
import { usePickStore, useTreeStore } from '@/stores';
import { usePickRenderModeStore, usePickStore, useTreeStore } from '@/stores';
import { pickDragOverlayStyle } from './dragOverlay.css';
import { PickCard } from './PickListViewer/PickCard';
import { PickRecord } from './PickListViewer/PickRecord';

export function DargOverlay({ elementClickPosition }: DargOverlayProps) {
const { isDragging: isFolderDragging, draggingFolderInfo } = useTreeStore();
const { isDragging: isPickDragging, draggingPickInfo } = usePickStore();
const { pickRenderMode } = usePickRenderModeStore();
const [mousePosition, setMousePosition] = useState({ x: -1, y: -1 });
const overlayStyle: CSSProperties = {
top: `${mousePosition.y}px`,
Expand Down Expand Up @@ -72,6 +74,14 @@ export function DargOverlay({ elementClickPosition }: DargOverlayProps) {
}

if (isPickDragging && draggingPickInfo) {
if (pickRenderMode === 'list') {
return (
<DndKitDragOverlay style={overlayStyle}>
<PickRecord pickInfo={draggingPickInfo} />
</DndKitDragOverlay>
);
}

return (
<DndKitDragOverlay style={overlayStyle}>
<div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import type { ReactNode } from 'react';
import { PickDnDCard } from './PickDnDCard';
import { PickDnDCardListLayout } from './PickDnDCardListLayout';
import { PickDndRecord } from './PickDndRecord';
import { PickDndRecordListLayout } from './PickDndRecordListLayout';
import type {
PickViewItemComponentProps,
PickViewItemListLayoutComponentProps,
} from './PickListViewer';
import type { PickInfoType } from '@/types';
import type { PickInfoType, PickRenderModeType } from '@/types';

export function DraggablePickListViewer({
pickList,
viewType = 'card',
viewType = 'list',
folderId,
}: PickListViewerProps) {
const { PickViewItemComponent, PickViewItemListLayoutComponent } =
DND_PICK_LIST_VIEW_TEMPLATES[viewType];

return (
<PickViewItemListLayoutComponent folderId={folderId}>
<PickViewItemListLayoutComponent folderId={folderId} viewType={viewType}>
{pickList.map((pickInfo) => (
<PickViewItemComponent key={pickInfo.id} pickInfo={pickInfo} />
))}
Expand All @@ -27,24 +29,23 @@ export function DraggablePickListViewer({
interface PickListViewerProps {
pickList: PickInfoType[];
folderId: number;
viewType?: DnDViewTemplateType;
viewType?: PickRenderModeType;
}

const DND_PICK_LIST_VIEW_TEMPLATES: Record<
DnDViewTemplateType,
PickRenderModeType,
DnDViewTemplateValueType
> = {
card: {
PickViewItemComponent: PickDnDCard,
PickViewItemListLayoutComponent: PickDnDCardListLayout,
},
list: {
PickViewItemComponent: PickDndRecord,
PickViewItemListLayoutComponent: PickDndRecordListLayout,
},
};

/**
* @description DnDViewTemplateType은 Drag&Drop이 가능한 UI 중 무엇을 보여줄지 나타냅니다. ex) card, list
*/
type DnDViewTemplateType = 'card';

interface DnDViewTemplateValueType {
PickViewItemListLayoutComponent: (
props: PickViewDnDItemListLayoutComponentProps
Expand All @@ -53,6 +54,9 @@ interface DnDViewTemplateValueType {
}

export type PickViewDnDItemListLayoutComponentProps =
PickViewItemListLayoutComponentProps<{ folderId: number }>;
PickViewItemListLayoutComponentProps<{
folderId: number;
viewType: PickRenderModeType;
}>;

export type PickViewDnDItemComponentProps = PickViewItemComponentProps;
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import { PickListSortableContext } from './PickListSortableContext';

export function PickDnDCardListLayout({
children,
viewType,
folderId,
}: PickViewDnDItemListLayoutComponentProps) {
return (
<div className={pickCardGridLayoutStyle}>
<PickListSortableContext folderId={folderId}>
<PickListSortableContext folderId={folderId} viewType={viewType}>
{children}
</PickListSortableContext>
</div>
Expand Down
103 changes: 103 additions & 0 deletions frontend/techpick/src/components/PickListViewer/PickDndRecord.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
'use client';

import { MouseEvent, useCallback, type CSSProperties } from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { usePickStore } from '@/stores';
import { isSelectionActive } from '@/utils';
import {
isActiveDraggingItemStyle,
selectedDragItemStyle,
} from './pickDnDCard.css';
import { getSelectedPickRange } from './pickDnDCard.util';
import { PickRecord } from './PickRecord';
import type { PickViewDnDItemComponentProps } from './PickListViewer';

export function PickDndRecord({ pickInfo }: PickViewDnDItemComponentProps) {
const {
selectedPickIdList,
selectSinglePick,
getOrderedPickIdListByFolderId,
focusPickId,
setSelectedPickIdList,
isDragging,
} = usePickStore();
const { linkInfo, id: pickId, parentFolderId } = pickInfo;
const { url } = linkInfo;
const isSelected = selectedPickIdList.includes(pickId);
const {
attributes,
listeners,
setNodeRef,
transform,
transition,
isDragging: isActiveDragging,
} = useSortable({
id: pickId,
data: {
id: pickId,
type: 'pick',
parentFolderId: parentFolderId,
},
});
const pickElementId = `pickId-${pickId}`;

const style: CSSProperties = {
transform: CSS.Transform.toString(transform),
transition,
opacity: 1,
};

const openUrl = useCallback(() => {
window.open(url, '_blank');
}, [url]);

const handleShiftSelect = (parentFolderId: number, pickId: number) => {
if (!focusPickId) {
return;
}

// 새로운 선택된 배열 만들기.
const orderedPickIdList = getOrderedPickIdListByFolderId(parentFolderId);

const newSelectedPickIdList = getSelectedPickRange({
orderedPickIdList,
startPickId: focusPickId,
endPickId: pickId,
});

setSelectedPickIdList(newSelectedPickIdList);
};

const handleClick = (
pickId: number,
event: MouseEvent<HTMLDivElement, globalThis.MouseEvent>
) => {
if (event.shiftKey && isSelectionActive(selectedPickIdList.length)) {
event.preventDefault();
handleShiftSelect(parentFolderId, pickId);
return;
}

selectSinglePick(pickId);
};

if (isDragging && isSelected && !isActiveDragging) {
return null;
}

return (
<>
<div ref={setNodeRef} {...attributes} {...listeners} style={style}>
<div
className={`${isSelected ? selectedDragItemStyle : ''} ${isActiveDragging ? isActiveDraggingItemStyle : ''}`}
onDoubleClick={openUrl}
onClick={(event) => handleClick(pickId, event)}
id={pickElementId}
>
<PickRecord pickInfo={pickInfo} />
</div>
</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { PickViewDnDItemListLayoutComponentProps } from './DraggablePickListViewer';
import { PickListSortableContext } from './PickListSortableContext';
import { PickRecordListLayout } from './PickRecordListLayout';

export function PickDndRecordListLayout({
children,
folderId,
viewType,
}: PickViewDnDItemListLayoutComponentProps) {
return (
<PickRecordListLayout>
<PickListSortableContext folderId={folderId} viewType={viewType}>
{children}
</PickListSortableContext>
</PickRecordListLayout>
);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
'use client';

import { SortableContext, rectSortingStrategy } from '@dnd-kit/sortable';
import { usePickStore } from '@/stores/pickStore/pickStore';
import {
SortableContext,
rectSortingStrategy,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { usePickStore } from '@/stores';
import { PickViewDnDItemListLayoutComponentProps } from './DraggablePickListViewer';

export function PickListSortableContext({
folderId,
children,
viewType,
}: PickViewDnDItemListLayoutComponentProps) {
const {
getOrderedPickIdListByFolderId,
Expand All @@ -23,11 +28,17 @@ export function PickListSortableContext({
)
: orderedPickIdList;

/**
* @description card일때와 vertical일 때 렌더링이 다릅니다.
*/
const strategy =
viewType === 'card' ? rectSortingStrategy : verticalListSortingStrategy;

return (
<SortableContext
id={`${folderId}`}
items={orderedPickIdListWithoutSelectedIdList}
strategy={rectSortingStrategy}
strategy={strategy}
>
{children}
</SortableContext>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import InfiniteLoader from 'react-window-infinite-loader';
import { colorVars } from 'techpick-shared';
import { PickRecord } from '@/components/PickListViewer/PickRecord';
import {
pickRecordListLayoutStyle,
pickRecordListLayoutInlineStyle,
RECORD_HEIGHT,
} from '@/components/PickListViewer/pickRecordListLayout.css';
import { usePickStore } from '@/stores';
Expand Down Expand Up @@ -62,7 +62,7 @@ export function PickListViewerInfiniteScroll(
>
{({ onItemsRendered, ref }) => (
<List
style={pickRecordListLayoutStyle}
style={pickRecordListLayoutInlineStyle}
onItemsRendered={onItemsRendered}
itemSize={RECORD_HEIGHT}
itemCount={itemCount}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client';
import { PickViewItemListLayoutComponentProps } from './PickListViewer';
import { pickRecordListLayoutStyle } from './pickRecordListLayout.css';

export function PickRecordListLayout({
children,
}: PickViewItemListLayoutComponentProps) {
return <div className={pickRecordListLayoutStyle}>{children}</div>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { CSSProperties } from 'react';
import type { CSSProperties } from 'react';
import { style } from '@vanilla-extract/css';
import { sizes, space } from 'techpick-shared';

export const RECORD_HEIGHT = 100;

export const pickRecordListLayoutStyle: CSSProperties = {};
export const pickRecordListLayoutInlineStyle: CSSProperties = {};

export const pickRecordListLayoutStyle = style({
display: 'flex',
flexDirection: 'column',
gap: space['12'],
width: sizes['full'],
height: sizes['full'],
overflowY: 'scroll',
});
1 change: 1 addition & 0 deletions frontend/techpick/src/stores/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { useTagStore } from './tagStore';
export { usePickStore } from './pickStore/pickStore';
export { useTreeStore } from './dndTreeStore/dndTreeStore';
export { usePickRenderModeStore } from './pickRenderModeStore';
24 changes: 24 additions & 0 deletions frontend/techpick/src/stores/pickRenderModeStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import type {
PickRenderModeAction,
PickRenderModeState,
} from './pickRenderModeStore.type';

const initialState: PickRenderModeState = {
pickRenderMode: 'list',
};

export const usePickRenderModeStore = create<
PickRenderModeState & PickRenderModeAction
>()(
immer((set) => ({
...initialState,

setPickRenderMode: (newPickRenderMode) => {
set((state) => {
state.pickRenderMode = newPickRenderMode;
});
},
}))
);
9 changes: 9 additions & 0 deletions frontend/techpick/src/stores/pickRenderModeStore.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { PickRenderModeType } from '@/types';

export type PickRenderModeState = {
pickRenderMode: PickRenderModeType;
};

export type PickRenderModeAction = {
setPickRenderMode: (newPickRenderMode: PickRenderModeType) => void;
};
4 changes: 4 additions & 0 deletions frontend/techpick/src/types/PickRenderModeType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @description PickRenderModeType은 Pick의 렌더링 UI 중 무엇을 보여줄지 나타냅니다. ex) card, list
*/
export type PickRenderModeType = 'card' | 'list';
1 change: 1 addition & 0 deletions frontend/techpick/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export type * from './dnd.type';
export type { PickDraggableObjectType } from './PickDraggableObjectType';
export type { FolderDraggableObjectType } from './FolderDraggableObjectType';
export type { PickToFolderDroppableObjectType } from './PickToFolderDroppableObjectType';
export type { PickRenderModeType } from './PickRenderModeType';

0 comments on commit c6e5ae2

Please sign in to comment.