feat(dimentorin): slicing landing - articles page
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,72 @@
|
|||||||
|
import { Button } from "@imphnen-frontend-service/ui/atoms"
|
||||||
|
import { cn, Show } from "@imphnen-frontend-service/utils"
|
||||||
|
import { FC } from "react"
|
||||||
|
|
||||||
|
export type ArticleCardProps = {
|
||||||
|
variant?: "default" | "recent" | "featured"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ArticleCard: FC<ArticleCardProps> = ({ variant = 'default' }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
variant === "recent" && "md:grid md:grid-cols-2 md:gap-7 xl:flex xl:items-center",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"w-full h-auto aspect-16/10 overflow-hidden mb-8 md:h-60 md:w-full xl:aspect-auto",
|
||||||
|
variant === "featured" && "md:h-[300px]",
|
||||||
|
variant === "recent" && "md:h-auto md:w-full md:aspect-15/7 md:mb-0 xl:aspect-square xl:w-[162px] xl:h-auto",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/image/59de8a682dfbe42455613ea07477ff3e30532c1f.webp"
|
||||||
|
alt="Cover's Article"
|
||||||
|
className={cn("w-full object-cover", variant === "recent" && "h-full")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={cn("leading-tight", variant === "recent" && "xl:flex-1")}>
|
||||||
|
<div className="w-max bg-primary-200 text-primary-600 px-3 py-1 text-xs font-medium rounded-4xl mb-4 xl:mb-[15px]">
|
||||||
|
5 min read
|
||||||
|
</div>
|
||||||
|
<h1
|
||||||
|
className={cn(
|
||||||
|
"text-[15px] text-neutral-800 font-semibold mb-4 line-clamp-2 md:text-[19px] xl:mb-[23px]",
|
||||||
|
variant === "featured" && "text-[19px] md:text-[23px]",
|
||||||
|
variant === "recent" && "mb-7 xl:text-[27px]"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
</h1>
|
||||||
|
<Show condition={variant !== "recent"}>
|
||||||
|
<p
|
||||||
|
className={cn(
|
||||||
|
"text-xs text-neutral-600 mb-6 md:text-[15px] md:mb-8 xl:text-[19px]",
|
||||||
|
variant === "featured" && "text-[15px] md:text-[19px] md:mb-6",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut et massa mi. Aliquam in hendrerit urna. Pellentesque sit amet sapien fringilla, mattis ligula consectetur, ultrices mauris.
|
||||||
|
</p>
|
||||||
|
</Show>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex justify-between items-center text-xs text-neutral-600 md:text-[15px] xl:text-[19px]",
|
||||||
|
variant === "default" && "mb-4",
|
||||||
|
variant === "featured" && "text-[15px] md:text-[19px] xl:text-base",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<p>Writer’s Name</p>
|
||||||
|
<p>14 March 2025</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show condition={variant === "default"}>
|
||||||
|
<Button type="button" size="sm" className="px-2.5 py-2">
|
||||||
|
Baca Artikel
|
||||||
|
</Button>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { ReactElement, useRef, useState } from "react";
|
||||||
|
import { ArticleCard } from "./_components/card/article";
|
||||||
|
import { cn, For } from "@imphnen-frontend-service/utils";
|
||||||
|
import { Button } from "@imphnen-frontend-service/ui/atoms";
|
||||||
|
import { motion, useInView, Variants } from "framer-motion";
|
||||||
|
|
||||||
|
const CATEGORIES = ['UI/UX Design', 'Software/Web Dev', 'Data & AI', 'Cloud & DevOps', 'Cybersecurity', 'IT & Network', 'Project Management', 'QA & Testing'] as const
|
||||||
|
type Category = typeof CATEGORIES[number]
|
||||||
|
|
||||||
|
export default function Components(): ReactElement {
|
||||||
|
const [activeTab, setActiveTab] = useState<Category>('UI/UX Design')
|
||||||
|
|
||||||
|
const ref = useRef(null)
|
||||||
|
const isInView = useInView(ref, { once: true, amount: 0.2 })
|
||||||
|
|
||||||
|
const containerVariants: Variants = {
|
||||||
|
hidden: { opacity: 0 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
transition: {
|
||||||
|
staggerChildren: 0.1,
|
||||||
|
delayChildren: 0.2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const childVariants: Variants = {
|
||||||
|
hidden: { opacity: 0, y: 20 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: {
|
||||||
|
duration: 0.4,
|
||||||
|
ease: [0.25, 0.46, 0.45, 0.94],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main ref={ref}>
|
||||||
|
<motion.section
|
||||||
|
className="w-full p-8 md:py-14 md:px-[60px] lg:py-16 lg:px-20"
|
||||||
|
variants={containerVariants}
|
||||||
|
initial="hidden"
|
||||||
|
animate={isInView ? "visible" : "hidden"}
|
||||||
|
>
|
||||||
|
<div className="max-w-7xl mx-auto mb-8 md:mb-20">
|
||||||
|
<motion.h1
|
||||||
|
className="text-[23px] font-semibold text-neutral-800 mb-9 md:text-[29px] xl:text-[46px] xl:font-bold"
|
||||||
|
variants={childVariants}
|
||||||
|
>
|
||||||
|
Featuring Articles
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<div className="grid gap-12 xl:grid-cols-2">
|
||||||
|
<motion.div variants={childVariants}>
|
||||||
|
<ArticleCard variant="featured" />
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<motion.h1
|
||||||
|
className="text-[19px] text-neutral-800 font-semibold mb-10 md:text-[29px] xl:text-[37px] xl:mb-12"
|
||||||
|
variants={childVariants}
|
||||||
|
>
|
||||||
|
Recent Articles
|
||||||
|
</motion.h1>
|
||||||
|
<div className="grid gap-10">
|
||||||
|
<For data={Array.from({ length: 3 })}>
|
||||||
|
{(_, index) => (
|
||||||
|
<motion.div key={index} variants={childVariants}>
|
||||||
|
<ArticleCard variant="recent" />
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<motion.h1
|
||||||
|
className="text-[19px] text-neutral-800 font-semibold mb-4 md:text-[23px] xl:text-[29px]"
|
||||||
|
variants={childVariants}
|
||||||
|
>
|
||||||
|
Category
|
||||||
|
</motion.h1>
|
||||||
|
<div className="scrollbar-hide mb-8 w-full overflow-auto mx-auto">
|
||||||
|
<motion.div className="min-w-max w-auto flex gap-x-3" variants={childVariants}>
|
||||||
|
<For data={CATEGORIES}>
|
||||||
|
{(category) => (
|
||||||
|
<Button
|
||||||
|
key={category}
|
||||||
|
type="button"
|
||||||
|
variant="text"
|
||||||
|
onClick={() => setActiveTab(category)}
|
||||||
|
className={cn(
|
||||||
|
"relative text-[10px] text-neutral-400 font-medium px-3 py-2 rounded-4xl md:text-xs md:font-semibold xl:text-[15px]",
|
||||||
|
"before:w-0 before:absolute before:h-0.5 before:mx-auto before:inset-x-0 before:bg-primary-500 hover:before:w-full before:bottom-0 before:left-0 before:transition-all before:duration-300",
|
||||||
|
activeTab === category && "text-primary-500 before:w-full"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{category}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-8 xl:grid-cols-3">
|
||||||
|
<For data={Array.from({ length: 3 })}>
|
||||||
|
{(_, index) => (
|
||||||
|
<motion.div key={index} variants={childVariants}>
|
||||||
|
<ArticleCard />
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.section>
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -16,7 +16,8 @@ const mappingPublicRoutes = [
|
|||||||
'/auth/new-password',
|
'/auth/new-password',
|
||||||
'/auth/register-mentor',
|
'/auth/register-mentor',
|
||||||
'/auth/register-mentor/pending',
|
'/auth/register-mentor/pending',
|
||||||
'/auth/register-mentor/success'
|
'/auth/register-mentor/success',
|
||||||
|
'/resources',
|
||||||
];
|
];
|
||||||
|
|
||||||
const mappingRoutePermissions = [
|
const mappingRoutePermissions = [
|
||||||
@@ -76,7 +77,7 @@ const mappingRoutePermissions = [
|
|||||||
|
|
||||||
const mappingPublicPrefixRoutes = [
|
const mappingPublicPrefixRoutes = [
|
||||||
'/mentoring',
|
'/mentoring',
|
||||||
'/resources',
|
'/articles',
|
||||||
]
|
]
|
||||||
|
|
||||||
//TODO : Fix this later
|
//TODO : Fix this later
|
||||||
|
|||||||
Reference in New Issue
Block a user