323 lines
8.8 KiB
TypeScript
323 lines
8.8 KiB
TypeScript
import { useState } from "react";
|
|
import { ArticleData, QAData, TagItem } from "./article";
|
|
import { useRouter } from "next/navigation";
|
|
import { Portal } from '@radix-ui/react-portal';
|
|
|
|
import Image from 'next/image';
|
|
import aImage from '../../components/images/a.png'
|
|
import qImage from '../../components/images/q.png';
|
|
import userImage from '../../components/images/user.png';
|
|
import React from "react";
|
|
import { FadeIn, FadeInStagger } from "../landing/fade-in";
|
|
import { useTranslation } from "react-i18next";
|
|
import { truncateString } from "@/lib/utils";
|
|
|
|
interface CardProps {
|
|
image: string;
|
|
title: string;
|
|
time: string;
|
|
summary: string;
|
|
}
|
|
|
|
|
|
export const Card: React.FC<ArticleData> = (articleData) => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
const router = useRouter();
|
|
|
|
const handleToggle = () => {
|
|
setOpen(!open);
|
|
};
|
|
|
|
const defaultImage = "https://gimg3.baidu.com/search/src=http%3A%2F%2Fpics3.baidu.com%2Ffeed%2F4ec2d5628535e5dd7c7cdc23847e08e2cc1b62c4.jpeg%40f_auto%3Ftoken%3D38327d5cbefb2cd45af58f8d47c0a0b5&refer=http%3A%2F%2Fwww.baidu.com&app=2021&size=f360,240&n=0&g=0n&q=75&fmt=auto?sec=1710435600&t=eafc0a27ff3295bb5b0b9065fc33a523"
|
|
|
|
|
|
return (
|
|
<article style={{ width: '100%', padding: '0px', border: '1px solid #fff', backgroundColor: '#f6f6f6', }}
|
|
onClick={() => {
|
|
|
|
router.push(`/details/${articleData.id}`, { scroll: false })
|
|
}}
|
|
|
|
className="cursor-pointer rounded border border-[#243c5a] overflow-hidden"
|
|
>
|
|
<figure
|
|
style={{ width: '100%', minHeight: "246px" }}
|
|
>
|
|
<img src={
|
|
(
|
|
articleData.image_url.includes("http")
|
|
? articleData.image_url
|
|
: process.env.NEXT_PUBLIC_CLIENT_IMAGE_URL + articleData.image_url
|
|
) || defaultImage
|
|
|
|
} alt={articleData.main_title} style={{ width: '100%', marginBottom: '8px' }} />
|
|
|
|
|
|
|
|
{/* 🔥 根据 model_parameter 来决定是否显示感叹号 */}
|
|
{(!articleData.model_parameter) && (
|
|
<div style={{
|
|
position: 'absolute',
|
|
bottom: '8px',
|
|
right: '8px',
|
|
width: '24px',
|
|
height: '24px',
|
|
backgroundColor: 'red',
|
|
borderRadius: '50%',
|
|
color: 'white',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
fontWeight: 'bold',
|
|
fontSize: '16px',
|
|
}}>
|
|
!
|
|
</div>
|
|
)}
|
|
|
|
|
|
|
|
|
|
</figure>
|
|
<div className='px-2 lg:px-6' style={{ height: '214px' }} >
|
|
<h3
|
|
className='text-left font-bold text-[#333333] text-[1.125rem] leading-[1.5rem]'
|
|
|
|
style={{
|
|
// lineHeight: "24px",
|
|
// fontSize: "24px", color: "#333333",
|
|
margin: "16px 0",
|
|
overflow: "hidden",
|
|
textOverflow: "ellipsis",
|
|
display: "-webkit-box",
|
|
WebkitLineClamp: 2,
|
|
WebkitBoxOrient: "vertical",
|
|
|
|
}}>{truncateString(articleData.main_title)}</h3>
|
|
<p style={{ padding: "6px 0", lineHeight: "24px", fontSize: "14px", color: "#808080" }}>{articleData.updated_time}</p>
|
|
<p style={{
|
|
lineHeight: "24px", fontSize: "16px", color: "#4c4c4c",
|
|
|
|
overflow: "hidden",
|
|
// whiteSpace: "nowrap",
|
|
textOverflow: "ellipsis",
|
|
|
|
display: "-webkit-box",
|
|
WebkitLineClamp: 3,
|
|
WebkitBoxOrient: "vertical",
|
|
|
|
}}>{truncateString(articleData.sub_title || articleData.summary)}</p>
|
|
{/* <button onClick={handleToggle}>查看详情</button> */}
|
|
</div>
|
|
|
|
|
|
{open && (
|
|
<Portal>
|
|
<div
|
|
style={{
|
|
position: 'fixed',
|
|
top: '50%',
|
|
left: '50%',
|
|
transform: 'translate(-50%, -50%)',
|
|
background: '#fff',
|
|
padding: '16px',
|
|
border: '2px solid #333',
|
|
}}
|
|
>
|
|
{/* 内容详情 */}
|
|
{/* <button onClick={handleToggle}>关闭</button> */}
|
|
</div>
|
|
</Portal>
|
|
)}
|
|
</article>
|
|
);
|
|
};
|
|
|
|
interface QACardProps {
|
|
question: string;
|
|
questionAvatar: string;
|
|
answer: string;
|
|
answerAvatar: string;
|
|
timestamp: string;
|
|
author: string;
|
|
}
|
|
|
|
|
|
export const QACard: React.FC<QAData> = (item) => {
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
const router = useRouter();
|
|
|
|
const handleToggle = () => {
|
|
setOpen(!open);
|
|
};
|
|
return (
|
|
// bg-secondary
|
|
<div className="qa-card pt-10 lg:pr-16 mb-0 cursor-pointer"
|
|
|
|
onClick={() => {
|
|
|
|
router.push(`/qa/${item.id}`)
|
|
}}
|
|
>
|
|
<div className=" h-20 mb-[1.5rem]">
|
|
{/* <img src={questionAvatar} alt="Questioner Avatar" className="avatar" /> */}
|
|
<figure className='float-left w-[56px] h-full' >
|
|
<Image src={qImage} width={36} alt="Questioner Avatar" className="avatar" />
|
|
</figure>
|
|
|
|
<h3
|
|
className='ml-0 line-clamp-2 lg:line-clamp-3 leading-[1.7rem] text-[16px] lg:text-[20px] font-bold'
|
|
style={{
|
|
// fontSize: "20px",
|
|
// fontWeight: "bold",
|
|
|
|
// overflow: "hidden",
|
|
// textOverflow: "ellipsis",
|
|
// display: "-webkit-box",
|
|
// WebkitLineClamp: 2,
|
|
// WebkitBoxOrient: "vertical",
|
|
}}
|
|
>{truncateString(item.question)}</h3>
|
|
</div>
|
|
|
|
<div className=" h-20 mb-[1.875rem]">
|
|
{/* <img src={answerAvatar} alt="Answerer Avatar" className="avatar" /> */}
|
|
|
|
<figure className='float-left w-[3.5rem] h-full ' >
|
|
<Image src={aImage} width={36} alt="Answer Avatar" className="" />
|
|
</figure>
|
|
|
|
<p
|
|
className='ml-0 pl-0 line-clamp-2 lg:line-clamp-3 text-[14px] lg:text-[18px] text-[#4D4D4D] '
|
|
// style={{
|
|
// fontSize: "18px",
|
|
// color: "#4D4D4D",
|
|
|
|
// overflow: "hidden",
|
|
// textOverflow: "ellipsis",
|
|
// display: "-webkit-box",
|
|
// WebkitLineClamp: 3,
|
|
// WebkitBoxOrient: "vertical",
|
|
// }}
|
|
>{truncateString(item.answer)}</p>
|
|
</div>
|
|
|
|
|
|
<div className="details flex justify-between pb-[2.25rem]" style={{ borderBottom: '1px solid #EBEBEB' }}>
|
|
<div className='px-0 flex items-center justify-start'>
|
|
|
|
<figure className='w-[3.5rem]' >
|
|
<Image src={userImage} width={36} alt="admin Author" className="" />
|
|
</figure>
|
|
<h5
|
|
className='text-[14px] lg:text-[16px] text-[#1A1A1A] font-bold'
|
|
// style={{
|
|
// fontSize: '16px',
|
|
// fontWeight: 'bold',
|
|
// color: '#1A1A1A'
|
|
// }}
|
|
>{item.id}</h5>
|
|
</div>
|
|
|
|
<div
|
|
className="timestamp text-[14px] lg:text-[16px]"
|
|
style={{
|
|
color: "#999999",
|
|
|
|
}}
|
|
>{item.updated_time}</div>
|
|
</div>
|
|
|
|
</div>
|
|
);
|
|
};
|
|
|
|
|
|
export interface TagsViewsProps {
|
|
isQA: boolean
|
|
selectedCategory: string
|
|
categoriesRef: React.MutableRefObject<TagItem[]>
|
|
onChange: (category: string) => any
|
|
onClickQA: () => any
|
|
}
|
|
|
|
|
|
export const TagsViews: React.FC<TagsViewsProps> = React.memo(({
|
|
isQA,
|
|
selectedCategory,
|
|
categoriesRef,
|
|
onChange,
|
|
onClickQA
|
|
}) => {
|
|
// console.log('ChildComponent 渲染');
|
|
const activeColor = '#1A1A1A'
|
|
|
|
const activeStyle = {
|
|
|
|
}
|
|
|
|
const defStyle = {
|
|
|
|
}
|
|
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<FadeIn>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
gap: '16px',
|
|
justifyContent: 'center',
|
|
flexWrap: 'wrap',
|
|
marginBottom: '32px',
|
|
}}
|
|
>
|
|
{categoriesRef.current
|
|
.map((item, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => {
|
|
onChange(item.value)
|
|
}}
|
|
style={{
|
|
// fontSize: "20px",
|
|
// padding: '8px',
|
|
// background: selectedCategory === category ? '#007BFF' : '#fff',
|
|
color: !isQA && selectedCategory === item.value ? activeColor : '#666666',
|
|
// ...activeStyle,
|
|
marginBottom: '8px',
|
|
}}
|
|
className={`text-[#666666] text-[0.875rem] lg:text-[1.25rem] p-[0.2rem] lg:p-[0.5rem]`}
|
|
>
|
|
{item.name}
|
|
</button>
|
|
))}
|
|
|
|
|
|
<div>
|
|
<button
|
|
onClick={() => {
|
|
onClickQA()
|
|
}}
|
|
style={{
|
|
// fontSize: "20px",
|
|
// padding: '8px',
|
|
// background: selectedCategory === category ? '#007BFF' : '#fff',
|
|
// color: selectedCategory === category ? '#666666' : '#1A1A1A',
|
|
marginBottom: '8px',
|
|
color: isQA ? activeColor : '#666666',
|
|
}}
|
|
className="text-[#666666] text-[0.875rem] lg:text-[1.25rem] p-[0.2rem] lg:p-[0.5rem]"
|
|
>
|
|
{t("article.qa")}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</FadeIn>
|
|
|
|
);
|
|
}); |