extract props
This commit is contained in:
parent
7afb21f1f0
commit
4203f06af0
7 changed files with 260 additions and 190 deletions
161
src/App.tsx
161
src/App.tsx
|
@ -1,8 +1,9 @@
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
import { AnnoymousNickNameProvider } from './AuthorData';
|
||||||
import { CommentInput, CommentItem, CommentListContainer, CommentPagination, PostListControls, SubCommentData } from './Comment';
|
import { CommentInput, CommentItem, CommentListContainer, CommentPagination, PostListControls, SubCommentData } from './Comment';
|
||||||
import CommentHeader from './CommentHeader';
|
import CommentHeader from './CommentHeader';
|
||||||
import { Footer } from './Footer';
|
import { Footer } from './Footer';
|
||||||
import { GalleryContent } from './Gallery';
|
import { GalleryContent, GalleryContentHeader } from './Gallery';
|
||||||
import { GalleryTitleHeader } from './GalleryTitleHeader';
|
import { GalleryTitleHeader } from './GalleryTitleHeader';
|
||||||
import { GlobalNavigationBar, Header, VisitHistory } from './Header';
|
import { GlobalNavigationBar, Header, VisitHistory } from './Header';
|
||||||
import { LoginBox } from './Sidebar';
|
import { LoginBox } from './Sidebar';
|
||||||
|
@ -106,7 +107,6 @@ const tableData: TableRowData[] = [
|
||||||
views: "",
|
views: "",
|
||||||
recommendations: "",
|
recommendations: "",
|
||||||
isNews: true,
|
isNews: true,
|
||||||
titleLinkUrl: '#', // Add actual URL
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -164,66 +164,105 @@ const comments: SubCommentData[] = [
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<AnnoymousNickNameProvider value="썬갤러">
|
||||||
<Header />
|
<div>
|
||||||
<GlobalNavigationBar />
|
<Header />
|
||||||
<VisitHistory />
|
<GlobalNavigationBar />
|
||||||
<div className='relative w-[1450px] mx-auto'>
|
<VisitHistory recentVisits={[
|
||||||
<main
|
{
|
||||||
className='w-[1160px] m-[20px_auto_0]'
|
id: 1,
|
||||||
>
|
name: "워썬더",
|
||||||
<section className='' >
|
isMinor: true,
|
||||||
<GalleryTitleHeader />
|
},
|
||||||
<div
|
{
|
||||||
className='border-custom-blue-dark border w-[1158px]'
|
id: 2,
|
||||||
/>
|
name: "배틀그라운드",
|
||||||
<GalleryContent />
|
isMinor: false,
|
||||||
<CommentHeader />
|
},
|
||||||
<CommentListContainer>
|
{
|
||||||
<CommentItem comment={{
|
id: 3,
|
||||||
id: 1,
|
name: "리그오브레전드",
|
||||||
author: { type: "nickname", nickname: "동아리망했다" },
|
isMinor: false,
|
||||||
text: '너 지금 상현이햄을 ■■라고',
|
},
|
||||||
timestamp: '03.31 17:44:25',
|
{
|
||||||
showDelete: true,
|
id: 4,
|
||||||
}} />
|
name: "발로란트",
|
||||||
<CommentItem comment={{
|
isMinor: false,
|
||||||
id: 2,
|
},
|
||||||
author: { type: "IP", ip: "218.144" },
|
{
|
||||||
text: '그냥 미국인인데 조센징들은 왜 조선계라고 못 넣어서 안달일까',
|
id: 5,
|
||||||
timestamp: '03.31 18:16:45',
|
name: "오버워치",
|
||||||
showDelete: true,
|
isMinor: true,
|
||||||
subComments: comments,
|
}
|
||||||
}} />
|
]} />
|
||||||
<CommentItem comment={{
|
<div className='relative w-[1450px] mx-auto'>
|
||||||
id: 3,
|
<main
|
||||||
author: { type: "IP", ip: "123.245" },
|
className='w-[1160px] m-[20px_auto_0]'
|
||||||
text: 'aaa',
|
>
|
||||||
timestamp: '03.31 18:16:45',
|
<section className='' >
|
||||||
showDelete: true,
|
<GalleryTitleHeader title='워썬더 갤러리' />
|
||||||
}} />
|
<div
|
||||||
</CommentListContainer>
|
className='border-custom-blue-dark border w-[1158px]'
|
||||||
<CommentPagination currentPage={1} maxPage={2} />
|
/>
|
||||||
<CommentInput />
|
<GalleryContentHeader kind='일반'
|
||||||
<PostListControls owner />
|
title={'아 e글 유파들이 고도 왜 안올리는지 알았다'}
|
||||||
<div className='flex justify-between'>
|
author={{
|
||||||
<div style={{
|
type: "IP",
|
||||||
width: "840px",
|
ip: "183.96",
|
||||||
}}>
|
}}
|
||||||
<GalleryTable data={tableData} />
|
date='2025.02.04 21:32:47'
|
||||||
<PostListControls />
|
views={1234}
|
||||||
|
recommendations={12}
|
||||||
|
commentCount={9}
|
||||||
|
/>
|
||||||
|
<GalleryContent />
|
||||||
|
<CommentHeader commentCount={9} />
|
||||||
|
<CommentListContainer>
|
||||||
|
<CommentItem comment={{
|
||||||
|
id: 1,
|
||||||
|
author: { type: "nickname", nickname: "동아리망했다" },
|
||||||
|
text: '너 지금 상현이햄을 ■■라고',
|
||||||
|
timestamp: '03.31 17:44:25',
|
||||||
|
showDelete: true,
|
||||||
|
}} />
|
||||||
|
<CommentItem comment={{
|
||||||
|
id: 2,
|
||||||
|
author: { type: "IP", ip: "218.144" },
|
||||||
|
text: '그냥 미국인인데 조센징들은 왜 조선계라고 못 넣어서 안달일까',
|
||||||
|
timestamp: '03.31 18:16:45',
|
||||||
|
showDelete: true,
|
||||||
|
subComments: comments,
|
||||||
|
}} />
|
||||||
|
<CommentItem comment={{
|
||||||
|
id: 3,
|
||||||
|
author: { type: "IP", ip: "123.245" },
|
||||||
|
text: 'aaa',
|
||||||
|
timestamp: '03.31 18:16:45',
|
||||||
|
showDelete: true,
|
||||||
|
}} />
|
||||||
|
</CommentListContainer>
|
||||||
|
<CommentPagination currentPage={1} maxPage={2} />
|
||||||
|
<CommentInput />
|
||||||
|
<PostListControls owner />
|
||||||
|
<div className='flex justify-between'>
|
||||||
|
<div style={{
|
||||||
|
width: "840px",
|
||||||
|
}}>
|
||||||
|
<GalleryTable data={tableData} />
|
||||||
|
<PostListControls />
|
||||||
|
</div>
|
||||||
|
<div style={{
|
||||||
|
width: "300px",
|
||||||
|
}}>
|
||||||
|
<LoginBox />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
</section>
|
||||||
width: "300px",
|
</main>
|
||||||
}}>
|
</div>
|
||||||
<LoginBox />
|
<Footer />
|
||||||
</div>
|
</div >
|
||||||
</div>
|
</AnnoymousNickNameProvider>
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
<Footer />
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
89
src/AuthorData.tsx
Normal file
89
src/AuthorData.tsx
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import { createContext, useContext, useMemo } from "react";
|
||||||
|
|
||||||
|
export type AuthorData = {
|
||||||
|
// 운영자
|
||||||
|
type: "operator";
|
||||||
|
} | {
|
||||||
|
// 고닉
|
||||||
|
// 중복 불가능 닉네임
|
||||||
|
type: "nickname";
|
||||||
|
nickname: string;
|
||||||
|
// 파딱, 주딱 구분을 위한 userType
|
||||||
|
userType?: "manager" | "submanager"; // Optional, if applicable
|
||||||
|
} | {
|
||||||
|
// 유동닉
|
||||||
|
type: "IP";
|
||||||
|
// IP 주소
|
||||||
|
ip: string;
|
||||||
|
|
||||||
|
tempNickname?: string; // Optional, if applicable
|
||||||
|
} | {
|
||||||
|
// 반유동닉
|
||||||
|
// 중복 가능 닉네임
|
||||||
|
type: "semi-nickname";
|
||||||
|
nickname: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const NicknameImagePath = {
|
||||||
|
"주딱": "/fix_managernik.gif",
|
||||||
|
"파딱": "/fix_sub_managernik.gif",
|
||||||
|
"반유동": "/nik.gif",
|
||||||
|
"default": "/fix_nik.gif"
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnnoymousNickName = createContext("ㅇㅇ");
|
||||||
|
export const AnnoymousNickNameProvider = AnnoymousNickName.Provider;
|
||||||
|
|
||||||
|
export function NickName({ author } : {
|
||||||
|
author: AuthorData,
|
||||||
|
}) {
|
||||||
|
const defaultNickname = useContext(AnnoymousNickName);
|
||||||
|
|
||||||
|
const nickname = useMemo(() => {
|
||||||
|
switch (author.type) {
|
||||||
|
case "nickname":
|
||||||
|
return author.nickname;
|
||||||
|
case "semi-nickname":
|
||||||
|
return author.nickname;
|
||||||
|
case "IP":
|
||||||
|
return author.tempNickname ?? defaultNickname;
|
||||||
|
case "operator":
|
||||||
|
return "운영자";
|
||||||
|
default:
|
||||||
|
return defaultNickname;
|
||||||
|
}
|
||||||
|
}, [author, defaultNickname])
|
||||||
|
|
||||||
|
return <>
|
||||||
|
{/* Author Name Span */}
|
||||||
|
<span className="inline-block max-w-[81%] align-top text-ellipsis overflow-hidden whitespace-nowrap">
|
||||||
|
{/* Inner em/span for potential finer control if needed */}
|
||||||
|
<em className="not-italic leading-[13px]">
|
||||||
|
{nickname}
|
||||||
|
</em>
|
||||||
|
</span>
|
||||||
|
{/* Author IP */}
|
||||||
|
{author?.type === "IP" && (
|
||||||
|
<span className="font-tahoma text-[11px] text-custom-gray-medium tracking-[-0.05em] ml-[3px]">
|
||||||
|
({author.ip})
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{/* Author Icon Placeholder */}
|
||||||
|
{author?.type !== "IP" && (
|
||||||
|
<a className="text-custom-gray-dark ml-0.5 inline-block">
|
||||||
|
{/* Replace with actual icon component or img tag */}
|
||||||
|
<img
|
||||||
|
alt="icon"
|
||||||
|
src={
|
||||||
|
author?.type === "nickname" ? (
|
||||||
|
author?.userType === "manager" ? NicknameImagePath["주딱"] :
|
||||||
|
author?.userType === "submanager" ? NicknameImagePath["파딱"] :
|
||||||
|
NicknameImagePath["default"]
|
||||||
|
) : NicknameImagePath["반유동"]
|
||||||
|
}
|
||||||
|
className="align-middle cursor-pointer w-3 h-3" // Example size
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { Separator } from "./Separator";
|
import { Separator } from "./Separator";
|
||||||
import { AuthorData } from "./table";
|
import { AuthorData } from './AuthorData';
|
||||||
import { cn } from "./util/cn";
|
import { cn } from "./util/cn";
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,37 @@
|
||||||
import { Separator } from "./Separator"
|
import { Separator } from "./Separator"
|
||||||
|
import { AuthorData, NickName } from './AuthorData';
|
||||||
|
|
||||||
function GalleryContentHeader() {
|
export interface GalleryContentHeaderProps {
|
||||||
|
title: string;
|
||||||
|
kind: string;
|
||||||
|
author: AuthorData;
|
||||||
|
date: string;
|
||||||
|
views?: number;
|
||||||
|
recommendations?: number;
|
||||||
|
/**
|
||||||
|
* Number of comments on the post
|
||||||
|
*/
|
||||||
|
commentCount?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GalleryContentHeader({
|
||||||
|
title,
|
||||||
|
kind,
|
||||||
|
author,
|
||||||
|
date,
|
||||||
|
views = 0,
|
||||||
|
recommendations = 0,
|
||||||
|
commentCount = 0,
|
||||||
|
}: GalleryContentHeaderProps) {
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
{/* Outer container with margin, padding, and bottom border */}
|
{/* Outer container with margin, padding, and bottom border */}
|
||||||
<div className="mt-4 mb-[29px] pb-[11px] border-b border-solid border-gray-200">
|
<div className="mt-4 mb-[29px] pb-[11px] border-b border-solid border-gray-200">
|
||||||
{/* Post Title */}
|
{/* Post Title */}
|
||||||
<h3 className="px-0.5 mb-[7px] text-sm font-bold">
|
<h3 className="px-0.5 mb-[7px] text-sm font-bold">
|
||||||
<span> [일반] </span>
|
<span> [{kind}] </span>
|
||||||
<span>
|
<span>
|
||||||
아 e글 유파들이 고도 왜 안올리는지 알았다
|
{title}
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -19,16 +41,10 @@ function GalleryContentHeader() {
|
||||||
>
|
>
|
||||||
{/* Left section: Author, IP, Timestamp */}
|
{/* Left section: Author, IP, Timestamp */}
|
||||||
<div>
|
<div>
|
||||||
<span>
|
<NickName author={author} />
|
||||||
{/* author name */}
|
|
||||||
<em className="not-italic"> 썬갤러 </em> {/* Adjusted em styling for clarity */}
|
|
||||||
</span>
|
|
||||||
<span className="font-tahoma text-[11px] text-gray-500 ml-1">
|
|
||||||
(110.15)
|
|
||||||
</span>
|
|
||||||
<span className="cursor-default">
|
<span className="cursor-default">
|
||||||
<Separator />
|
<Separator />
|
||||||
2025.02.04 21:32:47
|
{date}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -37,11 +53,11 @@ function GalleryContentHeader() {
|
||||||
className="pr-[7px]"
|
className="pr-[7px]"
|
||||||
>
|
>
|
||||||
<span className="cursor-default">
|
<span className="cursor-default">
|
||||||
조회 65
|
조회 {views}
|
||||||
</span>
|
</span>
|
||||||
<Separator />
|
<Separator />
|
||||||
<span className="cursor-default">
|
<span className="cursor-default">
|
||||||
추천 0
|
추천 {recommendations}
|
||||||
</span>
|
</span>
|
||||||
<Separator />
|
<Separator />
|
||||||
<span className="cursor-default">
|
<span className="cursor-default">
|
||||||
|
@ -50,7 +66,7 @@ function GalleryContentHeader() {
|
||||||
className="inline-block h-5 leading-5 px-2.5 bg-gray-200
|
className="inline-block h-5 leading-5 px-2.5 bg-gray-200
|
||||||
text-gray-700 border border-gray-300 rounded-full
|
text-gray-700 border border-gray-300 rounded-full
|
||||||
hover:bg-gray-300 hover:border-gray-400 text-xs">
|
hover:bg-gray-300 hover:border-gray-400 text-xs">
|
||||||
댓글 13
|
댓글 {commentCount}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -76,16 +92,7 @@ function GalleryRecommendation({
|
||||||
pt-[19px] w-fit box-content">
|
pt-[19px] w-fit box-content">
|
||||||
<div className="flex items-center justify-center overflow-hidden pb-2">
|
<div className="flex items-center justify-center overflow-hidden pb-2">
|
||||||
<div className="flex justify-end overflow-hidden w-[139px] mb-0.5">
|
<div className="flex justify-end overflow-hidden w-[139px] mb-0.5">
|
||||||
<div
|
<div className="text-custom-dropdown-text text-center pt-[10px] pl-[11px] w-[67px] font-bold">
|
||||||
style={{
|
|
||||||
width: "67px",
|
|
||||||
paddingTop: "10px",
|
|
||||||
paddingLeft: "11px",
|
|
||||||
textAlign: "center",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "rgb(85, 85, 85)"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<p className="text-base leading-[22px] text-[#d31900] font-bold"
|
<p className="text-base leading-[22px] text-[#d31900] font-bold"
|
||||||
>{recommendCount}</p>
|
>{recommendCount}</p>
|
||||||
<p
|
<p
|
||||||
|
@ -108,16 +115,12 @@ function GalleryRecommendation({
|
||||||
>
|
>
|
||||||
<em
|
<em
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "transparent",
|
|
||||||
backgroundImage:
|
|
||||||
'url("/sp_image.png")',
|
|
||||||
backgroundRepeat: "no-repeat",
|
|
||||||
backgroundPositionX: "0px",
|
backgroundPositionX: "0px",
|
||||||
backgroundPositionY: "-315px",
|
backgroundPositionY: "-315px",
|
||||||
display: "inline-block",
|
|
||||||
width: "56px",
|
width: "56px",
|
||||||
height: "56px",
|
height: "56px",
|
||||||
}}
|
}}
|
||||||
|
className="bg-sp-img inline-block"
|
||||||
></em>
|
></em>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -276,23 +279,18 @@ export function GalleryContent() {
|
||||||
return <article
|
return <article
|
||||||
className="text-custom-gray-dark text-[13px] font-apple"
|
className="text-custom-gray-dark text-[13px] font-apple"
|
||||||
>
|
>
|
||||||
<GalleryContentHeader />
|
|
||||||
<div style={{ lineHeight: "22px" }}>
|
<div style={{ lineHeight: "22px" }}>
|
||||||
<div style={{ marginBottom: "50px" }}>
|
<div style={{ marginBottom: "50px" }}>
|
||||||
<div
|
<div className="overflow-hidden relative">
|
||||||
style={{
|
|
||||||
overflow: "hidden",
|
|
||||||
position: "relative"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<span style={{ marginLeft: "10px" }}>
|
<span className="ml-[10px]">
|
||||||
<img
|
<img
|
||||||
style={{
|
style={{
|
||||||
maxWidth: "100%",
|
maxWidth: "100%",
|
||||||
width: "550px",
|
width: "550px",
|
||||||
height: "350px",
|
height: "350px",
|
||||||
}}
|
}}
|
||||||
|
alt="alt"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,24 @@
|
||||||
import { Separator } from "./Separator"
|
import { Separator } from "./Separator"
|
||||||
|
|
||||||
export function GalleryTitleHeader() {
|
interface GalleryTitleHeaderProps {
|
||||||
|
title?: string;
|
||||||
|
relatedGalleriesCount?: {
|
||||||
|
current: number;
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GalleryTitleHeader({
|
||||||
|
title = "워썬더 갤러리",
|
||||||
|
relatedGalleriesCount = { current: 2, total: 8 },
|
||||||
|
}: GalleryTitleHeaderProps = {}) {
|
||||||
return (
|
return (
|
||||||
<header className="bg-transparent h-[37px] mb-[3px] pt-[4px] text-gray-500">
|
<header className="bg-transparent h-[37px] mb-[3px] pt-[4px] text-gray-500">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<h2 className="mt-[-2px] mr-[6px] ml-[2px] text-[24px] max-w-[420px] font-[nanumGothic] tracking-[-1px] m-[2px_8px_0_3px] overflow-hidden whitespace-nowrap text-ellipsis text-custom-blue-dark">
|
<h2 className="mt-[-2px] mr-[6px] ml-[2px] text-[24px] max-w-[420px] font-[nanumGothic] tracking-[-1px] m-[2px_8px_0_3px] overflow-hidden whitespace-nowrap text-ellipsis text-custom-blue-dark">
|
||||||
<a className="text-custom-blue-dark font-bold">
|
<a className="text-custom-blue-dark font-bold">
|
||||||
워썬더 갤러리
|
{title}
|
||||||
<div className="bg-sp-img bg-no-repeat inline-block align-top ml-[4px] w-[22px] h-[22px] bg-[-195px_-844px] mt-[3px]">
|
<div className="bg-sp-img bg-no-repeat inline-block align-top ml-[4px] w-[22px] h-[22px] bg-[-195px_-844px] mt-[3px]">
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
@ -26,14 +37,20 @@ export function GalleryTitleHeader() {
|
||||||
</div>
|
</div>
|
||||||
<Separator />
|
<Separator />
|
||||||
<button className="cursor-pointer align-top font-sans">
|
<button className="cursor-pointer align-top font-sans">
|
||||||
연관 갤러리(2/8)
|
연관 갤러리({relatedGalleriesCount.current}/{relatedGalleriesCount.total})
|
||||||
<span className="mr-[2px] ml-[2px] hidden">
|
<span className="mr-[2px] ml-[2px] hidden">
|
||||||
</span>
|
</span>
|
||||||
<em className="bg-sp-img bg-no-repeat inline-block w-[9px] h-[5px] bg-[-115px_-43px] align-[1px] ml-[2px]">
|
<em className="bg-sp-img bg-no-repeat inline-block w-[9px] h-[5px] bg-[-115px_-43px] align-[1px] ml-[2px]">
|
||||||
</em>
|
</em>
|
||||||
</button>
|
</button>
|
||||||
<Separator />
|
<Separator />
|
||||||
<button className="cursor-pointer align-top">
|
<button className="cursor-pointer align-top"
|
||||||
|
onClick={() => {
|
||||||
|
prompt("해당 글의 주소입니다.\nCtrl+C를 눌러 클립보드로 복사하세요.",
|
||||||
|
window.location.href
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
갤주소 복사
|
갤주소 복사
|
||||||
</button>
|
</button>
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
|
@ -375,17 +375,20 @@ export function Header({
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function VisitHistory() {
|
export function VisitHistory({
|
||||||
|
recentVisits,
|
||||||
|
}: {
|
||||||
|
recentVisits?: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
isMinor?: boolean;
|
||||||
|
}[];
|
||||||
|
}) {
|
||||||
|
recentVisits = recentVisits ?? [];
|
||||||
// --- State for Interactivity (Example - not fully implemented in static version) ---
|
// --- State for Interactivity (Example - not fully implemented in static version) ---
|
||||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false); // To control the main dropdown visibility
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false); // To control the main dropdown visibility
|
||||||
const [activeTab, setActiveTab] = useState('recent'); // 'recent' or 'favorites' for the dropdown tabs
|
const [activeTab, setActiveTab] = useState('recent'); // 'recent' or 'favorites' for the dropdown tabs
|
||||||
|
|
||||||
// Dummy data matching the HTML snippet
|
|
||||||
const recentVisits = [
|
|
||||||
{ id: 1, name: '장르소설', isMinor: true },
|
|
||||||
{ id: 2, name: '실시간 베스트', isMinor: false },
|
|
||||||
// Add more items as needed
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-[1160px] mx-auto relative"> {/* Added relative positioning for children */}
|
<div className="w-[1160px] mx-auto relative"> {/* Added relative positioning for children */}
|
||||||
|
|
|
@ -1,27 +1,6 @@
|
||||||
|
import { AuthorData, NickName } from './AuthorData';
|
||||||
import { cn } from './util/cn';
|
import { cn } from './util/cn';
|
||||||
|
|
||||||
export type AuthorData = {
|
|
||||||
// 운영자
|
|
||||||
type: "operator"
|
|
||||||
} | {
|
|
||||||
// 고닉
|
|
||||||
// 중복 불가능 닉네임
|
|
||||||
type: "nickname",
|
|
||||||
nickname: string,
|
|
||||||
// 파딱, 주딱 구분을 위한 userType
|
|
||||||
userType?: "manager" | "submanager" // Optional, if applicable
|
|
||||||
} | {
|
|
||||||
// 유동닉
|
|
||||||
type: "IP",
|
|
||||||
// IP 주소
|
|
||||||
ip: string,
|
|
||||||
} | {
|
|
||||||
// 반유동닉
|
|
||||||
// 중복 가능 닉네임
|
|
||||||
type: "semi-nickname",
|
|
||||||
nickname: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Data Interface (Remains the same) ---
|
// --- Data Interface (Remains the same) ---
|
||||||
export interface TableRowData {
|
export interface TableRowData {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
|
@ -33,19 +12,7 @@ export interface TableRowData {
|
||||||
| "icon_ad" | "icon_dctrend";
|
| "icon_ad" | "icon_dctrend";
|
||||||
|
|
||||||
// e.g., "운영자", "고닉", "반유동", "유동닉"
|
// e.g., "운영자", "고닉", "반유동", "유동닉"
|
||||||
author?: {
|
author?: AuthorData;
|
||||||
type: "operator"
|
|
||||||
} | {
|
|
||||||
type: "nickname",
|
|
||||||
nickname: string,
|
|
||||||
userType?: "manager" | "submanager" // Optional, if applicable
|
|
||||||
} | {
|
|
||||||
type: "IP",
|
|
||||||
ip: string,
|
|
||||||
} | {
|
|
||||||
type: "semi-nickname",
|
|
||||||
nickname: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
date: string;
|
date: string;
|
||||||
|
|
||||||
|
@ -56,7 +23,6 @@ export interface TableRowData {
|
||||||
isAdOrSurvey?: boolean;
|
isAdOrSurvey?: boolean;
|
||||||
isNews?: boolean; // Handle the last row type specifically if needed
|
isNews?: boolean; // Handle the last row type specifically if needed
|
||||||
titleLinkUrl?: string; // Optional URL for title
|
titleLinkUrl?: string; // Optional URL for title
|
||||||
authorLinkUrl?: string; // Optional URL for author
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Child Component: TableRow ---
|
// --- Child Component: TableRow ---
|
||||||
|
@ -64,12 +30,6 @@ interface TableRowProps {
|
||||||
rowData: TableRowData;
|
rowData: TableRowData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NicknameImagePath = {
|
|
||||||
"주딱": "/fix_managernik.gif",
|
|
||||||
"파딱": "/fix_sub_managernik.gif",
|
|
||||||
"반유동": "/nik.gif",
|
|
||||||
"default": "/fix_nik.gif"
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TableRow({ rowData }: TableRowProps) {
|
export function TableRow({ rowData }: TableRowProps) {
|
||||||
const {
|
const {
|
||||||
|
@ -85,7 +45,6 @@ export function TableRow({ rowData }: TableRowProps) {
|
||||||
isAdOrSurvey,
|
isAdOrSurvey,
|
||||||
isNews,
|
isNews,
|
||||||
titleLinkUrl = "#",
|
titleLinkUrl = "#",
|
||||||
authorLinkUrl = "#",
|
|
||||||
author,
|
author,
|
||||||
} = rowData;
|
} = rowData;
|
||||||
|
|
||||||
|
@ -139,44 +98,9 @@ export function TableRow({ rowData }: TableRowProps) {
|
||||||
<td className={cn(
|
<td className={cn(
|
||||||
tdCenterClasses, // Base style for author cell
|
tdCenterClasses, // Base style for author cell
|
||||||
'text-[13px]', // Author cell often uses 13px base font size
|
'text-[13px]', // Author cell often uses 13px base font size
|
||||||
authorLinkUrl !== '#' ? 'cursor-pointer' : 'cursor-default', // Conditional cursor
|
|
||||||
)}>
|
)}>
|
||||||
{author?.type === "operator" ? (
|
{author && <NickName author={author} />}
|
||||||
<b className="font-bold">운영자</b>
|
{variant === "icon_dctrend" && "디시트렌드"}
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{/* Author Name Span */}
|
|
||||||
<span className="inline-block max-w-[81%] align-top text-ellipsis overflow-hidden whitespace-nowrap">
|
|
||||||
{/* Inner em/span for potential finer control if needed */}
|
|
||||||
<em className="not-italic leading-[13px]">
|
|
||||||
{author?.type === "nickname" ? author?.nickname : "ㅇㅇ"}
|
|
||||||
</em>
|
|
||||||
</span>
|
|
||||||
{/* Author IP */}
|
|
||||||
{author?.type === "IP" && (
|
|
||||||
<span className="font-tahoma text-[11px] text-custom-gray-medium tracking-[-0.05em] ml-[3px]">
|
|
||||||
({author.ip})
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{/* Author Icon Placeholder */}
|
|
||||||
{author?.type !== "IP" && (
|
|
||||||
<a href={authorLinkUrl} className="text-custom-gray-dark ml-0.5 inline-block">
|
|
||||||
{/* Replace with actual icon component or img tag */}
|
|
||||||
<img
|
|
||||||
alt="icon"
|
|
||||||
src={
|
|
||||||
author?.type === "nickname" ? (
|
|
||||||
author?.userType === "manager" ? NicknameImagePath["주딱"] :
|
|
||||||
author?.userType === "submanager" ? NicknameImagePath["파딱"] :
|
|
||||||
NicknameImagePath["default"]
|
|
||||||
) : NicknameImagePath["반유동"]
|
|
||||||
}
|
|
||||||
className="align-middle cursor-pointer w-3 h-3" // Example size
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</td>
|
</td>
|
||||||
<td className={tdCenterClasses}>{date}</td>
|
<td className={tdCenterClasses}>{date}</td>
|
||||||
<td className={tdCenterClasses}>{views}</td>
|
<td className={tdCenterClasses}>{views}</td>
|
||||||
|
|
Loading…
Add table
Reference in a new issue