235 lines
No EOL
9.6 KiB
TypeScript
235 lines
No EOL
9.6 KiB
TypeScript
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) ---
|
|
export interface TableRowData {
|
|
id: string | number;
|
|
category: string;
|
|
titleText: string;
|
|
commentCount?: number;
|
|
// e.g., "icon_notice", "icon_pic", "icon_txt", "icon_survey"
|
|
variant?: "icon_notice" | "icon_recoming" | "icon_recomovie" | "icon_pic" | "icon_txt" | "icon_survey"
|
|
| "icon_ad" | "icon_dctrend";
|
|
|
|
// e.g., "운영자", "고닉", "반유동", "유동닉"
|
|
author?: {
|
|
type: "operator"
|
|
} | {
|
|
type: "nickname",
|
|
nickname: string,
|
|
userType?: "manager" | "submanager" // Optional, if applicable
|
|
} | {
|
|
type: "IP",
|
|
ip: string,
|
|
} | {
|
|
type: "semi-nickname",
|
|
nickname: string,
|
|
}
|
|
|
|
date: string;
|
|
|
|
views: "" | "-" | number;
|
|
recommendations: "" | "-" | number;
|
|
// Special flags for row types affecting style/structure
|
|
isNotice?: boolean;
|
|
isAdOrSurvey?: boolean;
|
|
isNews?: boolean; // Handle the last row type specifically if needed
|
|
titleLinkUrl?: string; // Optional URL for title
|
|
authorLinkUrl?: string; // Optional URL for author
|
|
}
|
|
|
|
// --- Child Component: TableRow ---
|
|
interface TableRowProps {
|
|
rowData: TableRowData;
|
|
}
|
|
|
|
const NicknameImagePath = {
|
|
"주딱": "/fix_managernik.gif",
|
|
"파딱": "/fix_sub_managernik.gif",
|
|
"반유동": "/nik.gif",
|
|
"default": "/fix_nik.gif"
|
|
}
|
|
|
|
export function TableRow({ rowData }: TableRowProps) {
|
|
const {
|
|
id,
|
|
category,
|
|
titleText,
|
|
commentCount,
|
|
variant,
|
|
date,
|
|
views,
|
|
recommendations,
|
|
isNotice,
|
|
isAdOrSurvey,
|
|
isNews,
|
|
titleLinkUrl = "#",
|
|
authorLinkUrl = "#",
|
|
author,
|
|
} = rowData;
|
|
|
|
const iconTable = {
|
|
icon_notice: "0px 0px",
|
|
icon_recoming: "0px -193px",
|
|
icon_recomovie: "0px -193px",
|
|
icon_pic: "0px -100px",
|
|
icon_txt: "0px -123px",
|
|
icon_survey: "0px -170px",
|
|
icon_ad: "0px -193px",
|
|
icon_dctrend: "-3px -877px", // Example for news
|
|
}
|
|
const iconPosition = iconTable[variant ?? "icon_txt"]; // Default to undefined if not found
|
|
|
|
// --- Base Cell Styles ---
|
|
// Note: some styles like height/padding might be slightly different due to Tailwind defaults vs specific px
|
|
const tdBaseClasses = 'border-t border-custom-gray-light align-middle text-custom-gray-dark h-[25px] relative px-1 py-[2px]'; // Approximates tdBaseStyle
|
|
const tdCenterClasses = cn(tdBaseClasses, "text-center font-tahoma text-[11px] pt-[1px] pb-[2px]"); // Approximates tdCenterStyle
|
|
// --- Standard Row Rendering ---
|
|
return (
|
|
<tr className="bg-transparent hover:bg-custom-gray-light">
|
|
<td className={tdCenterClasses}>{isNews ? "" : id}</td>
|
|
<td className={cn(
|
|
tdCenterClasses,
|
|
'text-xs', // Base font size for category is 12px
|
|
(isAdOrSurvey || isNotice) && 'font-bold', // Conditional bold
|
|
)}>{category}</td>
|
|
<td className={cn(tdBaseClasses, "text-left text-[13px] h-[29px]")}>
|
|
<a href={titleLinkUrl} className={cn(
|
|
'text-custom-gray-dark inline-block max-w-[82%] align-middle text-ellipsis whitespace-nowrap overflow-hidden pt-[1px] leading-tight', // Approximates titleLinkStyle
|
|
"hover:underline",
|
|
isNews && '!text-custom-green', // News specific color override
|
|
(isNotice || isAdOrSurvey) && 'font-bold', // Title bold for Notice/Ad/Survey
|
|
)}>
|
|
{iconPosition && (
|
|
<em className="inline-block w-[15px] h-[15px] align-[-3px] mr-[7px] bg-no-repeat" style={{
|
|
background: `url("/icon_img.png?1012")`,
|
|
backgroundPosition: iconPosition,
|
|
}}></em>
|
|
)}
|
|
{/* Title text - boldness handled by titleLinkClasses */}
|
|
{titleText}
|
|
</a>
|
|
{commentCount !== undefined && commentCount > 0 && (
|
|
<span className="text-xs text-custom-gray-medium ml-1 align-middle tracking-[-0.05em]">
|
|
[{commentCount}]
|
|
</span>
|
|
)}
|
|
</td>
|
|
<td className={cn(
|
|
tdCenterClasses, // Base style for author cell
|
|
'text-[13px]', // Author cell often uses 13px base font size
|
|
authorLinkUrl !== '#' ? 'cursor-pointer' : 'cursor-default', // Conditional cursor
|
|
)}>
|
|
{author?.type === "operator" ? (
|
|
<b className="font-bold">운영자</b>
|
|
) : (
|
|
<>
|
|
{/* 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 className={tdCenterClasses}>{date}</td>
|
|
<td className={tdCenterClasses}>{views}</td>
|
|
<td className={tdCenterClasses}>{recommendations}</td>
|
|
</tr>
|
|
);
|
|
}
|
|
|
|
// --- Main Component: Table ---
|
|
export function GalleryTable(props: {
|
|
data: TableRowData[];
|
|
}) {
|
|
const { data } = props; // Destructure props to get data
|
|
|
|
// --- Base TH Styles ---
|
|
const thBaseClasses = 'bg-transparent h-[37px] border-t-2 border-b border-custom-blue-dark align-middle text-center text-custom-gray-dark font-appleDotum'; // Uses config colors
|
|
|
|
return (
|
|
<table className="bg-transparent border-collapse table-fixed text-xs font-apple w-full border-b border-custom-blue-dark">
|
|
{/* Screen Reader Only Caption */}
|
|
<caption className="relative w-0 text-[0px] leading-[0] -z-10">
|
|
갤러리 리스트
|
|
</caption>
|
|
{/* Column Widths */}
|
|
<colgroup>
|
|
<col style={{ width: "7%" }} />
|
|
<col style={{ width: 51 }} />
|
|
<col />
|
|
<col style={{ width: "18%" }} />
|
|
<col style={{ width: "6%" }} />
|
|
<col style={{ width: "6%" }} />
|
|
<col style={{ width: "6%" }} />
|
|
</colgroup>
|
|
{/* Table Header */}
|
|
<thead className="bg-transparent">
|
|
<tr className="bg-transparent">
|
|
<th className={thBaseClasses}> 번호 </th>
|
|
<th className={thBaseClasses}> 말머리 </th>
|
|
<th className={thBaseClasses}> 제목 </th>
|
|
<th className={thBaseClasses}> 글쓴이 </th>
|
|
<th className={thBaseClasses}> 작성일 </th>
|
|
<th className={thBaseClasses}> 조회 </th>
|
|
<th className={thBaseClasses}> 추천 </th>
|
|
{/* Note: Original CSS applied right border to all TH. Tailwind border utilities apply to all sides unless specified (e.g., border-l), so the above covers it. If you only wanted specific borders, you'd adjust.*/}
|
|
</tr>
|
|
</thead>
|
|
{/* Table Body */}
|
|
<tbody className="bg-transparent">
|
|
{data.map((row, index) => (
|
|
// Using id-index key for potential non-unique IDs between notices/regular posts
|
|
<TableRow key={`${row.id}-${index}`} rowData={row} />
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
);
|
|
} |