Merge pull request 'feature/featured-authors' (#111) from feature/featured-authors into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/111
This commit is contained in:
commit
56747b66a9
128
src/components/Card.tsx
Normal file
128
src/components/Card.tsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Components */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import Typography from "./typography/Typography";
|
||||||
|
import Heading from "./typography/Heading";
|
||||||
|
import Link from "./Link";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Props */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
type Props = {
|
||||||
|
/**
|
||||||
|
* Card component accept children
|
||||||
|
*/
|
||||||
|
children: React.ReactNode;
|
||||||
|
/**
|
||||||
|
* Styling the card component
|
||||||
|
*/
|
||||||
|
className?: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Card = ({ children, className }: Props) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames([
|
||||||
|
className,
|
||||||
|
"inline-flex flex-col justify-between p-4 items-start rounded border border-gray-75 gap-y-8 overflow-hidden",
|
||||||
|
])}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Avatar function
|
||||||
|
type AvatarProps = {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
Card.Avatar = function CardAvatar({ children }: AvatarProps) {
|
||||||
|
return <div>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Title function
|
||||||
|
Card.Title = function CardTitle({ children, className }: Props) {
|
||||||
|
return (
|
||||||
|
<Heading className={classNames([className, "select-none "])}>
|
||||||
|
{children}
|
||||||
|
</Heading>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// SubTitle function
|
||||||
|
Card.SubTitle = function CardSubTitle({ children, className }: Props) {
|
||||||
|
return (
|
||||||
|
<Typography className={classNames([className, ""])}>{children}</Typography>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Body function
|
||||||
|
Card.Body = function CardTitle({ children, className }: Props) {
|
||||||
|
return (
|
||||||
|
<Typography //
|
||||||
|
fontWeightVariant="normal"
|
||||||
|
className={classNames([className, "text-sm h-14 overflow-hidden "])}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cardheader function
|
||||||
|
Card.CardHeader = function CardCardHeader({ children, className }: Props) {
|
||||||
|
return (
|
||||||
|
<div className={classNames([className, "flex items-start gap-4"])}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cardcontent function
|
||||||
|
Card.CardContent = function CardCardContent({ children, className }: Props) {
|
||||||
|
return (
|
||||||
|
<div className={classNames([className, "flex flex-col gap-y-4 "])}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cardaction function
|
||||||
|
type CardActionProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string | undefined;
|
||||||
|
href?: string;
|
||||||
|
};
|
||||||
|
Card.CardAction = function CardCardAction({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
href = "#",
|
||||||
|
}: CardActionProps) {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={href}
|
||||||
|
className={classNames([className, "flex items-center gap-2"])}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// CardMedia function
|
||||||
|
type CardMediaProps = {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
className?: string | undefined;
|
||||||
|
src?: string;
|
||||||
|
};
|
||||||
|
Card.CardMedia = function CardCardMedia({
|
||||||
|
className,
|
||||||
|
src = "#",
|
||||||
|
}: CardMediaProps) {
|
||||||
|
return (
|
||||||
|
<img src={src} className={classNames([className, "w-full h-32 rounded"])} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Card;
|
188
src/components/FeaturedArticales.tsx
Normal file
188
src/components/FeaturedArticales.tsx
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Skeleton */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import "react-loading-skeleton/dist/skeleton.css";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Components */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import Typography from "./typography/Typography";
|
||||||
|
import SkeletonCard from "./SkeletonCard";
|
||||||
|
import AspectRatio from "./AspectRatio";
|
||||||
|
import Card from "./Card";
|
||||||
|
import Link from "./Link";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Data */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import Articales from "./Articales.json";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Icons */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import { ReactComponent as SVGArrowRight } from "assets/svg/arrow-right.svg";
|
||||||
|
import { ReactComponent as SVGCaretRight } from "assets/svg/caret-right.svg";
|
||||||
|
import { ReactComponent as SVGArrowLeft } from "assets/svg/arrow-left.svg";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Swiper */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import SwiperCore, { Navigation } from "swiper";
|
||||||
|
import { Pagination } from "swiper";
|
||||||
|
import "swiper/css/pagination";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import "./styles.css";
|
||||||
|
import "swiper/css";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* How many Skeleton cards should be added to the design */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
let twoCards: boolean = false;
|
||||||
|
let threeCards: boolean = false;
|
||||||
|
console.log(`Number of cards ${Articales.length}`);
|
||||||
|
if (Articales.length == 2) {
|
||||||
|
twoCards = true;
|
||||||
|
} else if (Articales.length == 3) {
|
||||||
|
threeCards = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwiperCore.use([Navigation]);
|
||||||
|
|
||||||
|
const FeaturedArticales = () => {
|
||||||
|
const navigationPrevRef = useRef(null);
|
||||||
|
const navigationNextRef = useRef(null);
|
||||||
|
const paginationRef = useRef(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="slider-wrapper Articales">
|
||||||
|
<div className="flex justify-end gap-2 my-2">
|
||||||
|
<div
|
||||||
|
className="prev inline-flex justify-center items-center
|
||||||
|
w-9 h-9 bg-blue-600 rounded cursor-pointer
|
||||||
|
opacity-0 md:opacity-100"
|
||||||
|
ref={navigationPrevRef}
|
||||||
|
>
|
||||||
|
<SVGArrowLeft className="w-6 h-6 fill-white "></SVGArrowLeft>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="next inline-flex justify-center items-center
|
||||||
|
w-9 h-9 bg-blue-600 rounded cursor-pointer
|
||||||
|
opacity-0 md:opacity-100"
|
||||||
|
ref={navigationNextRef}
|
||||||
|
>
|
||||||
|
<SVGArrowRight className="w-6 h-6 fill-white "></SVGArrowRight>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Swiper
|
||||||
|
slidesPerView={1.25}
|
||||||
|
slidesPerGroup={1}
|
||||||
|
loop={Articales.length > 4 ? true : false}
|
||||||
|
pagination={{ el: ".pagination", clickable: true }}
|
||||||
|
navigation={{
|
||||||
|
prevEl: ".prev",
|
||||||
|
nextEl: ".next",
|
||||||
|
}}
|
||||||
|
breakpoints={{
|
||||||
|
768: {
|
||||||
|
slidesPerView: 2,
|
||||||
|
slidesPerGroup: 2,
|
||||||
|
},
|
||||||
|
1024: {
|
||||||
|
slidesPerView: 2,
|
||||||
|
slidesPerGroup: 2,
|
||||||
|
},
|
||||||
|
1280: {
|
||||||
|
slidesPerView: 4,
|
||||||
|
slidesPerGroup: 4,
|
||||||
|
},
|
||||||
|
1580: {
|
||||||
|
slidesPerView: 4,
|
||||||
|
slidesPerGroup: 4,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
spaceBetween={25}
|
||||||
|
loopFillGroupWithBlank={true}
|
||||||
|
modules={[Pagination, Navigation]}
|
||||||
|
>
|
||||||
|
{Articales.map((Articale) => (
|
||||||
|
<SwiperSlide>
|
||||||
|
<Card className="flex-1">
|
||||||
|
<Card.CardContent>
|
||||||
|
<AspectRatio>
|
||||||
|
<AspectRatio.Content>
|
||||||
|
<img src={Articale.CoverImg} />
|
||||||
|
</AspectRatio.Content>
|
||||||
|
</AspectRatio>
|
||||||
|
|
||||||
|
<Card.Body className="h-14 overflow-hidden">
|
||||||
|
{Articale.Body}
|
||||||
|
</Card.Body>
|
||||||
|
</Card.CardContent>
|
||||||
|
|
||||||
|
<Card.CardAction href={Articale.Link}>
|
||||||
|
<Link>
|
||||||
|
<Typography className="text-blue-500 font-bold">
|
||||||
|
Read More
|
||||||
|
</Typography>
|
||||||
|
</Link>
|
||||||
|
<SVGCaretRight className="fill-blue-500 w-4 h-4" />
|
||||||
|
</Card.CardAction>
|
||||||
|
</Card>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{twoCards && [
|
||||||
|
<SwiperSlide className="hidden xl:block">
|
||||||
|
<SwiperSlide>
|
||||||
|
<SkeletonCard className="flex-1">
|
||||||
|
<SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Media />
|
||||||
|
<SkeletonCard.Body />
|
||||||
|
</SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Action />
|
||||||
|
</SkeletonCard>
|
||||||
|
</SwiperSlide>
|
||||||
|
</SwiperSlide>,
|
||||||
|
|
||||||
|
<SwiperSlide className="hidden xl:block">
|
||||||
|
<SwiperSlide>
|
||||||
|
<SkeletonCard className="flex-1">
|
||||||
|
<SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Media />
|
||||||
|
<SkeletonCard.Body />
|
||||||
|
</SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Action />
|
||||||
|
</SkeletonCard>
|
||||||
|
</SwiperSlide>
|
||||||
|
</SwiperSlide>,
|
||||||
|
]}
|
||||||
|
|
||||||
|
{threeCards && [
|
||||||
|
<SwiperSlide className="hidden xl:block">
|
||||||
|
<SwiperSlide>
|
||||||
|
<SkeletonCard className="flex-1">
|
||||||
|
<SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Media />
|
||||||
|
<SkeletonCard.Body />
|
||||||
|
</SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Action />
|
||||||
|
</SkeletonCard>
|
||||||
|
</SwiperSlide>
|
||||||
|
</SwiperSlide>,
|
||||||
|
]}
|
||||||
|
</Swiper>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="pagination my-6 w-full h-2 flex justify-center items-center
|
||||||
|
opacity-0 md:opacity-100"
|
||||||
|
ref={paginationRef}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FeaturedArticales;
|
169
src/components/FeaturedAuthors.tsx
Normal file
169
src/components/FeaturedAuthors.tsx
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Components */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import Heading from "./typography/Heading";
|
||||||
|
import SkeletonCard from "./SkeletonCard";
|
||||||
|
import { Button } from "./Button/Button";
|
||||||
|
import Avatar from "./Avatar";
|
||||||
|
import Card from "./Card";
|
||||||
|
import Link from "./Link";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Swiper */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import SwiperCore, { Navigation } from "swiper";
|
||||||
|
import "swiper/css/pagination";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import "./styles.css";
|
||||||
|
import "swiper/css";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Authors */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import Authors from "./Authors.json";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Icons */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import { ReactComponent as SVGCaretRight } from "assets/svg/caret-right.svg";
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Variables */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
SwiperCore.use([Navigation]);
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Number of Cards */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
let twoCards: boolean = false;
|
||||||
|
let threeCards: boolean = false;
|
||||||
|
console.log(`Number of cards ${Authors.length}`);
|
||||||
|
if (Authors.length == 2) {
|
||||||
|
twoCards = true;
|
||||||
|
} else if (Authors.length == 3) {
|
||||||
|
threeCards = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Featured authors component to display ...
|
||||||
|
*/
|
||||||
|
export default function FeaturedAuthors(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* The Title of Featured Authors section */}
|
||||||
|
<Heading className="text-center my-8">Featured Authors</Heading>
|
||||||
|
|
||||||
|
{/* Featured Authors section */}
|
||||||
|
<div className="slider-wrapper Authors">
|
||||||
|
<Swiper
|
||||||
|
slidesPerView={1.25}
|
||||||
|
slidesPerGroup={1}
|
||||||
|
spaceBetween={25}
|
||||||
|
loop={Authors.length > 4 ? true : false}
|
||||||
|
loopFillGroupWithBlank={false}
|
||||||
|
breakpoints={{
|
||||||
|
768: {
|
||||||
|
slidesPerView: 2,
|
||||||
|
slidesPerGroup: 2,
|
||||||
|
},
|
||||||
|
1024: {
|
||||||
|
slidesPerView: 2,
|
||||||
|
slidesPerGroup: 2,
|
||||||
|
},
|
||||||
|
1280: {
|
||||||
|
slidesPerView: 4,
|
||||||
|
slidesPerGroup: 4,
|
||||||
|
},
|
||||||
|
1580: {
|
||||||
|
slidesPerView: 4,
|
||||||
|
slidesPerGroup: 4,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Authors.map((card) => (
|
||||||
|
<SwiperSlide>
|
||||||
|
<Card className="flex-1">
|
||||||
|
<Card.CardContent>
|
||||||
|
<Card.CardHeader>
|
||||||
|
<Card.Avatar>
|
||||||
|
{card.img ? (
|
||||||
|
<Avatar
|
||||||
|
className="w-12 h-12"
|
||||||
|
src={card.img}
|
||||||
|
alt={card.Title}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Avatar
|
||||||
|
className="w-12 h-12"
|
||||||
|
src={card.img}
|
||||||
|
alt={card.Title}
|
||||||
|
>
|
||||||
|
{card.Title[0]}
|
||||||
|
</Avatar>
|
||||||
|
)}
|
||||||
|
</Card.Avatar>
|
||||||
|
<Card.Title>{card.Title}</Card.Title>
|
||||||
|
</Card.CardHeader>
|
||||||
|
<Card.Body>{card.Body}</Card.Body>
|
||||||
|
</Card.CardContent>
|
||||||
|
|
||||||
|
<Card.CardAction href={card.Link}>
|
||||||
|
<Link className="text-blue-500 font-bold ">See More</Link>
|
||||||
|
<SVGCaretRight className="fill-blue-500 w-4 h-4" />
|
||||||
|
</Card.CardAction>
|
||||||
|
</Card>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{twoCards && [
|
||||||
|
<SwiperSlide className="hidden xl:block">
|
||||||
|
<SkeletonCard className="flex-1">
|
||||||
|
<SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Header>
|
||||||
|
<SkeletonCard.Avatar />
|
||||||
|
<SkeletonCard.Title />
|
||||||
|
</SkeletonCard.Header>
|
||||||
|
<SkeletonCard.Body />
|
||||||
|
</SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Action />
|
||||||
|
</SkeletonCard>
|
||||||
|
</SwiperSlide>,
|
||||||
|
|
||||||
|
<SwiperSlide className="hidden xl:block">
|
||||||
|
<SkeletonCard className="flex-1">
|
||||||
|
<SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Header>
|
||||||
|
<SkeletonCard.Avatar />
|
||||||
|
<SkeletonCard.Title />
|
||||||
|
</SkeletonCard.Header>
|
||||||
|
<SkeletonCard.Body />
|
||||||
|
</SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Action />
|
||||||
|
</SkeletonCard>
|
||||||
|
</SwiperSlide>,
|
||||||
|
]}
|
||||||
|
|
||||||
|
{threeCards && [
|
||||||
|
<SwiperSlide className="hidden xl:block">
|
||||||
|
<SkeletonCard className="flex-1">
|
||||||
|
<SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Header>
|
||||||
|
<SkeletonCard.Avatar />
|
||||||
|
<SkeletonCard.Title />
|
||||||
|
</SkeletonCard.Header>
|
||||||
|
<SkeletonCard.Body />
|
||||||
|
</SkeletonCard.Content>
|
||||||
|
<SkeletonCard.Action />
|
||||||
|
</SkeletonCard>
|
||||||
|
</SwiperSlide>,
|
||||||
|
]}
|
||||||
|
</Swiper>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button emphasis="high" className="font-bold m-auto my-8">
|
||||||
|
Show All
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user