Skip to content
Merged
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
1 change: 1 addition & 0 deletions LP/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@tanstack/react-query": "^5.75.2",
"axios": "^1.9.0",
"clsx": "^2.1.1",
"lucide-react": "^0.510.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-hook-form": "^7.56.1",
Expand Down
Binary file added LP/public/cd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added LP/public/lp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion LP/src/api/lp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ export const fetchLpDetail = async (lpId: string | number): Promise<Lp> => {
};

return withTagIds;
};
};
48 changes: 48 additions & 0 deletions LP/src/components/CommentSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from "react";
import { useComments } from "../hooks/useComments";

interface CommentSectionProps {
LPid: string;
user: { id: number; name: string } | null;
}

const CommentSection = ({ LPid, user }: CommentSectionProps) => {
const { comments, comment, setComment, submitComment } = useComments(LPid);

return (
<div className="mt-6 w-full max-w-xl mx-auto px-4">
<form
onSubmit={(e) => {
e.preventDefault();
submitComment(comment);
}}
className="flex items-center gap-2 mb-4"
>
<input
type="text"
value={comment}
onChange={(e) => setComment(e.target.value)}
placeholder="댓글을 입력하세요"
className="flex-1 p-2 rounded bg-gray-800 text-white border border-gray-600"
/>
<button
type="submit"
className="px-4 py-2 rounded bg-blue-600 text-white"
disabled={!comment?.trim()}
>
등록
</button>
</form>
<ul className="space-y-2">
{comments?.map((c) => (
<li key={c.id} className="bg-gray-800 p-3 rounded text-sm text-white">
<div className="font-semibold">{c.user.name}</div>
<div className="text-gray-300">{c.content}</div>
</li>
))}
</ul>
</div>
);
};

export default CommentSection;
36 changes: 36 additions & 0 deletions LP/src/components/DeleteUserModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// src/components/DleteUserModal.tsx
import React from "react";

interface DeleteUserModalProps {
onDelete: () => void;
onCancel: () => void;
}

const DeleteUserModal = ({ onDelete, onCancel }: DeleteUserModalProps) => {
return (
<div className="fixed inset-0 bg-[rgba(0,0,0,0.5)] flex justify-center items-center z-50">
<div className="relative bg-[#2c2c2c] p-6 rounded-xl text-center text-white w-[300px] shadow-lg">
<button onClick={onCancel} className="absolute top-2 right-2 text-xl">
</button>
<p className="mb-6 mt-4">정말 탈퇴하시겠습니까?</p>
<div className="flex justify-center gap-4">
<button
onClick={onDelete}
className="bg-gray-300 text-black px-4 py-2 rounded"
>
</button>
<button
onClick={onCancel}
className="bg-pink-500 text-white px-4 py-2 rounded"
>
아니요
</button>
</div>
</div>
</div>
);
};

export default DeleteUserModal;
21 changes: 21 additions & 0 deletions LP/src/components/FAB.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Plus } from "lucide-react";

interface FABProps {
onClick: () => void;
icon?: React.ReactNode;
ariaLabel?: string;
}

const FAB = ({ onClick, icon = <Plus />, ariaLabel = "Add" }: FABProps) => {
return (
<button
onClick={onClick}
aria-label={ariaLabel}
className="fixed bottom-6 right-6 z-50 bg-pink-500 text-white rounded-full w-14 h-14 flex items-center justify-center text-2xl shadow-lg hover:bg-pink-600 transition-all"
>
{icon}
</button>
);
};

export default FAB;
13 changes: 5 additions & 8 deletions LP/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import { useAuthContext } from "../context/AuthContext";
import { useNavigate } from "react-router-dom";
import { FiSearch } from "react-icons/fi";
import { FiSearch } from "react-icons/fi";

interface HeaderProps {
onToggleSidebar: () => void;
Expand All @@ -16,10 +17,7 @@ const Header = ({ onToggleSidebar }: HeaderProps) => {
<header className="flex justify-between items-center px-6 py-4 bg-[#121212] z-50 h-16">
{/* 왼쪽: 햄버거 + 로고 */}
<div className="flex items-center gap-4">
<button
className="text-white text-2xl"
onClick={onToggleSidebar}
>
<button className="text-white text-2xl" onClick={onToggleSidebar}>
</button>
<h1
Expand All @@ -34,11 +32,10 @@ const Header = ({ onToggleSidebar }: HeaderProps) => {
<div className="flex items-center gap-4">
{/* 검색 아이콘 */}
<FiSearch className="text-white text-xl cursor-pointer" />


{isLoggedIn ? (
<>
<span className="text-white text-sm">
<span key={user?.name} className="text-white text-sm">
{user?.name ?? "회원"}님 반갑습니다.
</span>
<button
Expand Down Expand Up @@ -69,4 +66,4 @@ const Header = ({ onToggleSidebar }: HeaderProps) => {
);
};

export default Header;
export default React.memo(Header);
24 changes: 24 additions & 0 deletions LP/src/components/LPContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import { Lp } from "../types/lp";

interface LPContentProps {
lp: Lp;
}

const LPContent = ({ lp }: LPContentProps) => {
return (
<div className="text-center">
<h2 className="text-2xl font-bold mb-4">{lp.title}</h2>
<p className="text-sm text-gray-300 leading-relaxed">{lp.content}</p>
<div className="flex flex-wrap gap-2 mt-4 text-sm justify-center">
{lp.tags.map((tag) => (
<span key={tag.id} className="bg-gray-700 px-3 py-1 rounded-full">
#{tag.name}
</span>
))}
</div>
</div>
);
};

export default LPContent;
74 changes: 74 additions & 0 deletions LP/src/components/LPControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from "react";
import { Lp } from "../types/lp";

interface LPControlsProps {
editMode: boolean;
setEditMode: (value: boolean) => void;
lp: Lp;
editLp: () => void;
deleteLp: () => void;
setEditTitle: (value: string) => void;
setEditContent: (value: string) => void;
setEditThumbnail: (value: string) => void;
setEditTags: (value: string) => void;
}

const LPControls = ({
editMode,
setEditMode,
lp,
editLp,
deleteLp,
setEditTitle,
setEditContent,
setEditThumbnail,
setEditTags,
}: LPControlsProps) => {
return (
<div className="absolute top-6 right-6 flex gap-2">
{!editMode ? (
<>
<button
onClick={() => {
setEditMode(true);
setEditTitle(lp.title);
setEditContent(lp.content);
setEditThumbnail(lp.thumbnail);
setEditTags(lp.tags.map((tag) => tag.name).join(", "));
}}
className="flex items-center gap-1 px-3 py-1 border border-gray-500 rounded hover:bg-gray-700 transition-colors duration-200"
>
✏️ <span className="text-sm">수정</span>
</button>
<button
onClick={() => {
if (window.confirm("정말 삭제하시겠습니까?")) {
deleteLp();
}
}}
className="flex items-center gap-1 px-3 py-1 border border-gray-500 rounded hover:bg-red-700 transition-colors duration-200"
>
🗑️ <span className="text-sm">삭제</span>
</button>
</>
) : (
<>
<button
onClick={editLp}
className="px-3 py-1 bg-blue-600 rounded text-white text-sm"
>
저장
</button>
<button
onClick={() => setEditMode(false)}
className="px-3 py-1 bg-gray-600 rounded text-white text-sm"
>
취소
</button>
</>
)}
</div>
);
};

export default LPControls;
26 changes: 26 additions & 0 deletions LP/src/components/LPHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import { Lp } from "../types/lp";

interface LPHeaderProps {
lp: Lp;
}

const LPHeader = ({ lp }: LPHeaderProps) => {
return (
<div className="flex justify-center mb-4">
<div className="w-80 h-80 bg-black/30 rounded-lg shadow-md flex items-center justify-center relative">
<img
src={lp.thumbnail}
alt="LP"
className="w-60 h-60 rounded-full object-cover animate-spin border-[6px] border-gray-600"
/>
<div className="absolute w-8 h-8 bg-black rounded-full z-10" />
<span className="absolute bottom-2 right-2 text-xs text-gray-300 bg-black bg-opacity-50 px-2 py-1 rounded">
{new Date(lp.createdAt).toLocaleDateString("ko-KR")}
</span>
</div>
</div>
);
};

export default LPHeader;
Loading