| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- 'use client';
- import './style.scss';
- import Link from 'next/link';
- import { useSearchParams } from 'next/navigation';
- import Image, { ImageProps } from 'next/image';
- import { useState } from 'react';
- import Post from '@/types/forum/post';
- import { BoardListMeta } from '@/types/forum/boardMeta';
- import { formatDate, isHotPost, isNewPost } from '@/lib/utils/client';
- import { faThumbsUp, faEye, faClock } from '@fortawesome/free-regular-svg-icons';
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
- import NoticeListLayout from './NoticeListLayout';
- interface Props {
- boardListMeta: BoardListMeta;
- speaker: Post[];
- notice: Post[];
- list: Post[];
- startIndex: number;
- onChange: (_: number|undefined) => void;
- }
- function ImageWithFallback({
- src,
- fallbackSrc = '/resources/no-image.png',
- alt,
- ...option
- }: ImageProps & { fallbackSrc?: string }) {
- const [imgSrc, setImgSrc] = useState(src);
- return (
- <Image
- {...option}
- src={imgSrc}
- alt={alt}
- onError={() => setImgSrc(fallbackSrc)}
- />
- );
- }
- export default function AlbumListLayout({boardListMeta, speaker, notice, list, onChange}: Props)
- {
- const searchParams = useSearchParams();
- return (
- <>
- {!boardListMeta.exceptSpeaker && !boardListMeta.exceptNotice ? (
- <section className='notice-list-layout' aria-label='공지사항'>
- <article>
- <ul>
- <li>번호</li>
- <li>제목</li>
- <li>작성자</li>
- <li>작성일</li>
- <li>조회수</li>
- </ul>
- </article>
- <article>
- {/* 전체 공지 */}
- <NoticeListLayout isEnabled={!boardListMeta.exceptSpeaker} list={speaker} layout={boardListMeta.layout} />
- {/* 일반 공지 */}
- <NoticeListLayout isEnabled={!boardListMeta.exceptNotice} list={notice} layout={boardListMeta.layout} />
- </article>
- </section>
- ) : (
- <br hidden/>
- )}
- <div className={list.length > 0 ? 'album-list-layout' : 'grid p-10 text-center border-b mb-3'} aria-label='사진/영산 게시판'>
- {list.length > 0 ? (
- list.map(row => {
- const query = Object.fromEntries(searchParams.entries());
- const href = `/post/${row.id}${window.location.search}`;
- const isNew = isNewPost(boardListMeta.isNewIcon, row);
- const isHot = isHotPost(boardListMeta.isHotIcon, row);
- const createdAt = formatDate(row.createdAt);
- return (
- <div key={row.id}>
- <figure>
- <article>
- <Link href={href}>
- {row.thumbnail ? (
- <ImageWithFallback src={row.thumbnail} alt={row.subject} fill style={{ objectFit: 'cover' }} loading="lazy" />
- ) : (
- <Image src='/resources/no-image.png' alt={row.subject} loading='lazy' fill />
- )}
- </Link>
- </article>
- <dl>
- <dt>
- {row.boardPrefix && row.boardPrefixID && (
- <button type="button" onClick={() => onChange(row.boardPrefixID || undefined)}>
- [{row.boardPrefix.name}]
- </button>
- )}
- <Link href={{
- pathname: '/post/' + row.id,
- query: {
- ...query
- }
- }}
- >
- <em>{row.subject} {row.comments > 0 && (<span>[{row.comments}]</span>)}</em>
- {isNew && <span><img src='/resources/new.gif' alt='NEW'/></span>}
- {isHot && <span><img src='/resources/hot.gif' alt='HOT'/></span>}
- </Link>
- </dt>
- <dd>{row.name}</dd>
- </dl>
- <figcaption>
- <ul>
- <li><FontAwesomeIcon icon={faThumbsUp} /> {row.likes}</li>
- <li><FontAwesomeIcon icon={faEye} /> {row.views}</li>
- <li><FontAwesomeIcon icon={faClock} /> {createdAt}</li>
- </ul>
- </figcaption>
- </figure>
- </div>
- );
- })
- ) : (
- <p>등록된 게시글이 없습니다.</p>
- )}
- </div>
- </>
- );
- }
|