Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/app/dashboard/[id]/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import { Avatar } from '@/app/shared/components/common/Avatar'
import { useDragStore } from '../store/useDragStore'
import Tags from './Tags'

/**
* Renders a draggable card displaying its image, title, tags, due date, and assignee information.
*
* The card supports drag-and-drop interactions and prevents the default context menu from appearing on right-click.
*
* @param card - The card data to display.
* @param columnId - The identifier of the column containing this card.
*/
export default function Card({
card,
columnId,
Expand Down
7 changes: 7 additions & 0 deletions src/app/dashboard/[id]/Card/Tags.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { getColor } from '@/app/shared/lib/getColor'

/**
* Displays a list of tags with each tag assigned a consistent background and text color.
*
* Each tag's color is determined by a deterministic function based on its text, ensuring the same tag always receives the same color combination.
*
* @param tags - Array of tag strings to display.
*/
export default function Tags({ tags }: { tags: string[] }) {
//태그 컬러 - 랜덤 배정
//카드 생성 시 - 동일 태그 입력 불가하도록
Expand Down
7 changes: 7 additions & 0 deletions src/app/dashboard/[id]/Column/Column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import { cn } from '@/app/shared/lib/cn'
import { useCardMutation } from '../api/useCardMutation'
import Card from '../Card/Card'
import { useDragStore } from '../store/useDragStore'
/**
* Renders a column containing cards with drag-and-drop support for moving cards between columns.
*
* Displays the column title, card count, and provides UI controls for creating cards and configuring the column. Handles drag-and-drop events to allow cards to be moved into the column, updating their assignment accordingly.
*
* @param column - The column data, including its unique identifier and title.
*/
export default function Column({ column }: { column: ColumnType }) {
const { id, title }: { id: number; title: string } = column
const { data, isLoading, error } = useCards(id)
Expand Down
9 changes: 9 additions & 0 deletions src/app/dashboard/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ import Column from './Column/Column'
import { useDragStore } from './store/useDragStore'
import type { Card } from './type/Card'

/**
* Renders a kanban-style dashboard with touch-based drag-and-drop functionality for cards.
*
* Enables users to move cards between columns using a long-press gesture on touch devices. Handles card movement visually by cloning the dragged card, updating its position during drag, and highlighting columns as potential drop targets. On drop, updates the card's column via mutation.
*
* @returns The dashboard UI with columns, cards, and an option to add new columns.
*
* @remark Drag-and-drop is activated by a 300ms long press on a card. Only touch events are supported for dragging.
*/
export default function DashboardID() {
const dashboard = 15120
const { data: columns, isLoading, error } = useColumns(dashboard)
Expand Down
17 changes: 17 additions & 0 deletions src/app/shared/components/common/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,30 @@ const customColors = [
'#e292e0',
]

/**
* Extracts the initial character from a nickname for avatar display.
*
* Returns the uppercase letter if the first character is an English alphabet letter, the character itself if it is a Korean Hangul syllable, or a question mark if neither condition is met.
*
* @param nickname - The user's nickname.
* @returns The initial character to display in the avatar.
*/
function getInitial(nickname: string): string {
const firstChar = nickname.trim().charAt(0)
if (/[a-zA-Z]/.test(firstChar)) return firstChar.toUpperCase()
if (/[가-힣]/.test(firstChar)) return firstChar
return '?'
}

/**
* Displays a user avatar as a circular image or a colored initial based on the provided nickname and optional image URL.
*
* If an image URL is given, the avatar shows the image. Otherwise, it displays the initial character of the nickname on a colored background.
*
* @param nickname - The user's nickname, used to determine the initial and background color.
* @param imageUrl - Optional URL of the user's avatar image.
* @param size - Optional size in pixels for the avatar's width and height. Defaults to 36.
*/
export function Avatar({ nickname, imageUrl, size = 36 }: AvatarProps) {
const initial = getInitial(nickname)
const bgColor = getColor(nickname, customColors)
Expand Down
9 changes: 9 additions & 0 deletions src/app/shared/lib/getColor.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/**
* Maps a string to a deterministic index within a custom color array.
*
* Computes a numeric hash from the input {@link text} and returns an index corresponding to a position in {@link customColors}.
*
* @param text - The input string to be mapped.
* @param customColors - The array of color strings to map into.
* @returns An index within {@link customColors} based on the hash of {@link text}.
*/
export function getColor(text: string, customColors: string[]): number {
const hash = text.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
const index = hash % customColors.length
Expand Down