Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
11 changes: 8 additions & 3 deletions src/app/(with-header-sidebar)/dashboard/[id]/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { CardData } from '@/types/dashboardView';
import type { CardData } from '@/types/dashboardView';
import { useModal } from '@/app/(with-header-sidebar)/mydashboard/_hooks/useModal';
import Modal from '@/app/(with-header-sidebar)/mydashboard/_components/modal/Modal';
import CardInfo from './card-detail/CardInfo';
import HeaderMenu from './card-detail/HeaderMenu';
import styles from './Card.module.css';

interface Props {
item: CardData;
index: number;
columnTitle: string;
}

function Card({ item, index }: Props) {
function Card({ item, index, columnTitle }: Props) {
const { isOpen, openModal, isClosing, closeModal } = useModal();

if (!item || !item.id) {
Expand Down Expand Up @@ -39,8 +41,11 @@ function Card({ item, index }: Props) {
onClose={closeModal}
title={item.title}
hasCloseButton={true}
headerComponent={() => (
<HeaderMenu closeModal={closeModal} cardId={item.id} />
)}
>
<CardInfo card={item} />
<CardInfo card={item} columnTitle={columnTitle} />
</Modal>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@ function Column({ color, title, totalCount, id, items }: ColumnData) {
className={styles.dropContext}
>
{items.map((item, index) =>
item ? <Card key={item.id} item={item} index={index} /> : null
item ? (
<Card
key={item.id}
item={item}
index={index}
columnTitle={title}
/>
) : null
)}
{provided.placeholder}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,43 @@
margin-top: 20px;
}

.infoContainer {
display: flex;
flex-direction: column;
gap: 18px;
max-width: 330px;
margin-top: 16px;
}

.labelArea {
display: flex;
align-items: center;
gap: 12px;
}

.tagContainer {
display: flex;
gap: 6px;
}

.description {
color: var(--black);
font-size: 12px;
font-weight: 400;
line-height: 18px;
}

.imageWrapper {
position: relative;
width: 325px;
height: 170px;
}

.imageWrapper img {
border-radius: 6px;
object-fit: cover;
}

@media screen and (min-width: 768px) {
.cardInfo {
display: flex;
Expand All @@ -16,11 +53,27 @@

.infoContainer {
flex: 7;
max-width: 450px;
margin-top: 0;
}

.description {
font-size: 14px;
line-height: 24px;
}

.imageWrapper {
width: 445px;
height: 260px;
}
}

@media screen and (min-width: 1200px) {
.cardInfo {
gap: 39px;
}

.labelArea {
gap: 20px;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
import { CardData } from '@/types/dashboardView';
import type { CardData } from '@/types/dashboardView';
import Assignment from './Assignment';
import Tag from '@/components/card/Tag';
import ColumnLabel from '@/components/card/ColumnLabel';
import Pipe from '@/components/svg/Pipe';
import Image from 'next/image';
import styles from './CardInfo.module.css';

export default function CardInfo({ card }: { card: CardData }) {
interface CardInfoProps {
card: CardData;
columnTitle: string;
}

export default function CardInfo({ card, columnTitle }: CardInfoProps) {
const { description, tags, imageUrl } = card;

return (
<div className={styles.cardInfo}>
<div className={styles.assignmentContainer}>
<Assignment card={card} />
</div>
<div className={styles.infoContainer}>์นด๋“œ ์ƒ์„ธ๋‚ด์šฉ + ๋Œ“๊ธ€ ์˜์—ญ</div>
<div className={styles.infoContainer}>
<div className={styles.labelArea}>
<div>
<ColumnLabel name={columnTitle} />
</div>
<Pipe />
<div className={styles.tagContainer}>
{tags.map((tag, index) => (
<Tag key={index} name={tag} />
))}
</div>
</div>
<p className={styles.description}>{description}</p>
{imageUrl && (
<div className={styles.imageWrapper}>
<Image src={imageUrl} alt="ํ• ์ผ ์ด๋ฏธ์ง€" fill />
</div>
)}
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.headerMenu {
display: flex;
align-items: center;
margin-right: 16px;
position: relative;
}

.moreButton {
display: inline-flex;
align-items: center;
}

.menuContainer {
position: absolute;
z-index: 999;
top: 40px;
right: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import More from '@/components/svg/More';
import type { Menu } from '@/types/menu';
import MenuDropdown from '@/components/MenuDropdown';
import { useMenu } from '@/hooks/useMenu';
import styles from './HeaderMenu.module.css';
import { deleteCard } from '@/lib/cardService';
import { useRouter } from 'next/navigation';
import useDashboardStore from '@/store/dashboardStore';

interface HeaderMenuProps {
cardId: number;
closeModal: () => void;
}

export default function HeaderMenu({ cardId, closeModal }: HeaderMenuProps) {
const router = useRouter();
const { dashboard } = useDashboardStore();
const { isMenuVisible, toggleMenu } = useMenu();

const handelDeleteClick = async () => {
await deleteCard(cardId);
closeModal();
router.replace(`/dashboard/${dashboard?.id}`);
};

const cardMenus: Menu[] = [
{ name: '์ˆ˜์ •ํ•˜๊ธฐ', handleOnClick: () => console.log('์ˆ˜์ •ํ•˜๊ธฐ ํด๋ฆญ') },
{ name: '์‚ญ์ œํ•˜๊ธฐ', handleOnClick: handelDeleteClick },
];

return (
<div className={styles.headerMenu}>
<button type="button" onClick={toggleMenu} className={styles.moreButton}>
<More />
</button>
{isMenuVisible && (
<div className={styles.menuContainer}>
<MenuDropdown menus={cardMenus} />
</div>
)}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const DEFAULT_MEMBERS_STATE: MemberState = {
members: [],
};

const useMember = (dashboardId: string, pageSize = 4) => {
const useMember = (dashboardId: string | null, pageSize = 4) => {
const [memberState, setMemberState] = useState<MemberState>(
DEFAULT_MEMBERS_STATE
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@
color: var(--black-100);
}

.close {
.closeButtonWrapper {
position: relative;
width: 24px;
height: 24px;
transition: 200ms;
}

.close:hover {
filter: brightness(2);
transform: rotate(90deg);
.closeButton {
display: inline-flex;
align-items: center;
}

@keyframes fadeIn {
Expand Down Expand Up @@ -107,4 +107,9 @@
flex: 1;
color: var(--black-100);
}

.closeButtonWrapper {
width: 32px;
height: 32px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface ModalProps {
allowDimClose?: boolean;
title?: string;
hasCloseButton?: boolean;
headerComponent?: React.ComponentType;
headerComponent?: React.ComponentType<unknown>;
children: ReactNode;
}

Expand Down Expand Up @@ -59,18 +59,16 @@ export default function Modal({
{title && <h3 className={styles.title}>{title}</h3>}
{Component && <Component />}
{hasCloseButton && (
<button
onClick={onClose}
className={styles.close}
aria-label="Close modal"
>
<Image
src="/icons/x_lg.svg"
alt="Close icon"
width={24}
height={24}
/>
</button>
<div className={styles.closeButtonWrapper}>
<button
onClick={onClose}
aria-label="Close modal"
type="button"
className={styles.closeButton}
>
<Image src="/icons/x_lg.svg" alt="Close icon" fill />
</button>
</div>
)}
</div>
{children}
Expand Down
1 change: 0 additions & 1 deletion src/app/(with-header-sidebar)/mydashboard/_hooks/useApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export default function useApi<
const [error, setError] = useState<AxiosError | null>(null);

const fetchData = useCallback(async () => {
// TODO if (loading) return; add?
setIsLoading(true);
setError(null);

Expand Down
18 changes: 1 addition & 17 deletions src/components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Image from 'next/image';
import styles from './Avatar.module.css';
import { getRandomColor } from '@/utils/colorUtils';

interface AvatarProps {
name: string | number;
Expand Down Expand Up @@ -36,20 +37,3 @@ export default function Avatar({
</>
);
}

const getRandomColor = (name: string) => {
const hash = [...name].reduce(
(acc, char) => acc + char.charCodeAt(0) * 31,
0
);
const getValue = (offset: number) => {
const baseValue = (((hash >> offset) % 0xff) % 76) + 180;
const maxValue = 225;
return Math.min(baseValue, maxValue);
};
const red = getValue(0);
const green = getValue(8);
const blue = getValue(16);

return `rgb(${red}, ${green}, ${blue})`;
};
40 changes: 40 additions & 0 deletions src/components/MenuDropdown.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

.menuDropdown {
border-radius: 6px;
border: 1px solid var(--gray-300);
background: var(--white);
box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, 0.08);
padding: 6px;
display: flex;
flex-direction: column;
gap: 5px;
animation: slideDown 0.3s ease-out;
}

.button {
border-radius: 4px;
color: var(--black);
font-size: 14px;
font-weight: 400;
transition:
background-color 0.3s ease,
color 0.3s ease,
transform 0.3s ease;
white-space: nowrap;
padding: 5px 16px;
}

.button:hover {
background-color: var(--violet-light);
color: var(--violet);
}
Loading