forked from UKSOURCE/hailearning.edu.vn
feat: complete publications and research sections and resolve conflicts
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import { AboutData } from "../../about/types";
|
||||
|
||||
interface AboutFeaturesProps {
|
||||
data: AboutData["features"];
|
||||
}
|
||||
|
||||
const AboutFeatures = ({ data }: AboutFeaturesProps) => {
|
||||
return (
|
||||
<section
|
||||
className="choose-us-section-2 section-padding fix bg-cover"
|
||||
style={{ backgroundImage: `url(${data.backgroundImage})` }}
|
||||
>
|
||||
<div className="container">
|
||||
<div className="choose-us-wrapper-2">
|
||||
<div className="row g-4">
|
||||
<div className="col-lg-6">
|
||||
<div className="choose-us-image">
|
||||
<img src={data.image} alt="img" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<div className="feature-content">
|
||||
<div className="section-title mb-0">
|
||||
<span className="sub-title-2 wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">{data.heading}</h2>
|
||||
</div>
|
||||
<p className="text">{data.description}</p>
|
||||
{data.items.map((item, index) => (
|
||||
<div key={index} className="choose-us-box">
|
||||
<div className="icon">
|
||||
<img src={item.icon} alt="img" />
|
||||
</div>
|
||||
<div className="content">
|
||||
<h5>{item.title}</h5>
|
||||
<p>{item.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<Link href={data.ctaButton.href} className="theme-btn">
|
||||
{data.ctaButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutFeatures;
|
||||
@@ -1,39 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
import { AboutData } from '../../about/types';
|
||||
|
||||
interface AboutHeroProps {
|
||||
data: AboutData['hero'];
|
||||
}
|
||||
|
||||
const AboutHero = ({ data }: AboutHeroProps) => {
|
||||
return (
|
||||
<section className="breadcrumb-wrapper fix bg-cover" style={{ backgroundImage: `url(${data.backgroundImage})` }}>
|
||||
<div className="shape">
|
||||
<img src="/assets/img/inner-page/shape.png" alt="img" />
|
||||
</div>
|
||||
<div className="container">
|
||||
<div className="page-heading">
|
||||
<h1 className="breadcrumb-title">{data.title}</h1>
|
||||
{Array.isArray(data.breadcrumb) && (
|
||||
<ul className="breadcrumb-list">
|
||||
{data.breadcrumb.map((item, index) => (
|
||||
<li key={index}>
|
||||
{index === data.breadcrumb.length - 1 ? (
|
||||
item
|
||||
) : (
|
||||
<>
|
||||
<Link href="/">{item}</Link>
|
||||
<i className="fa-solid fa-chevron-right ms-2 me-2"></i>
|
||||
</>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutHero;
|
||||
@@ -1,28 +0,0 @@
|
||||
import { AboutData } from "../../about/types";
|
||||
|
||||
interface AboutIntroProps {
|
||||
data: AboutData["intro"];
|
||||
}
|
||||
|
||||
const AboutIntro = ({ data }: AboutIntroProps) => {
|
||||
return (
|
||||
<section className="intro-section section-padding fix pb-0">
|
||||
<div className="container">
|
||||
<div className="section-title-area">
|
||||
<div className="section-title">
|
||||
<span className="sub-title-2 wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">{data.heading}</h2>
|
||||
</div>
|
||||
<p>{data.description}</p>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="intro-image tp-clip-anim p-relative">
|
||||
<img src={data.image} alt="img" className="tp-anim-img" data-animate="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutIntro;
|
||||
@@ -1,79 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import { AboutData } from "../../about/types";
|
||||
|
||||
interface AboutMissionProps {
|
||||
data: AboutData["mission"];
|
||||
}
|
||||
|
||||
const AboutMission = ({ data }: AboutMissionProps) => {
|
||||
return (
|
||||
<section className="about-section section-padding fix pb-0">
|
||||
<div className="top-shape">
|
||||
<img src={data.images.globeShape} alt="img" />
|
||||
</div>
|
||||
<div className="container">
|
||||
<div className="about-wrapper">
|
||||
<div className="row g-4">
|
||||
<div className="col-lg-6">
|
||||
<div className="about-image">
|
||||
<img src={data.images.main} alt="img" className="wow img-custom-anim-left" />
|
||||
<div className="about-image-2">
|
||||
<img src={data.images.secondary} alt="img" className="wow img-custom-anim-right" />
|
||||
</div>
|
||||
<div className="bg-shape">
|
||||
<img src={data.images.bgShape} alt="img" />
|
||||
</div>
|
||||
<div className="plane-shape float-bob-y">
|
||||
<img src={data.images.planeShape} alt="img" />
|
||||
</div>
|
||||
<div className="top-shape float-bob-y">
|
||||
<img src={data.images.topShape} alt="img" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<div className="about-content">
|
||||
<div className="section-title mb-0">
|
||||
<span className="sub-title wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">{data.heading}</h2>
|
||||
</div>
|
||||
<p className="text wow fadeInUp" data-wow-delay=".3s">
|
||||
{data.description}
|
||||
</p>
|
||||
<div className="about-item wow fadeInUp" data-wow-delay=".5s">
|
||||
{data.items.map((item, index) => (
|
||||
<div key={index} className="content">
|
||||
<span>
|
||||
<img src={item.icon} alt="" className="me-2 d-inline-block" />
|
||||
{item.label}-
|
||||
</span>
|
||||
<p>{item.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<ul className="list wow fadeInUp" data-wow-delay=".3s">
|
||||
{data.features.map((feature, index) => (
|
||||
<li key={index}>
|
||||
<i className="fa-solid fa-chevrons-right"></i>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link
|
||||
href={data.ctaButton.href}
|
||||
className="theme-btn wow fadeInUp"
|
||||
data-wow-delay=".5s"
|
||||
>
|
||||
{data.ctaButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutMission;
|
||||
@@ -1,75 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import { AboutData } from "../../about/types";
|
||||
|
||||
interface AboutNewsProps {
|
||||
data: AboutData["news"];
|
||||
}
|
||||
|
||||
const AboutNews = ({ data }: AboutNewsProps) => {
|
||||
return (
|
||||
<section className="news-section section-padding fix pt-0">
|
||||
<div className="container">
|
||||
<div className="section-title-area">
|
||||
<div className="section-title">
|
||||
<span className="sub-title">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">{data.heading}</h2>
|
||||
</div>
|
||||
<Link href={data.ctaButton.href} className="theme-btn">
|
||||
{data.ctaButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="row">
|
||||
{data.items.map((item, index) => (
|
||||
<div key={index} className="col-xl-4 col-lg-6 col-md-6">
|
||||
<div className="news-card-item">
|
||||
<div className="news-image">
|
||||
<img src={item.thumbnail} alt="img" />
|
||||
<span>{item.category}</span>
|
||||
<div className="news-layer-wrapper">
|
||||
<div
|
||||
className="news-layer-image"
|
||||
style={{ backgroundImage: `url('${item.thumbnail}')` }}
|
||||
></div>
|
||||
<div
|
||||
className="news-layer-image"
|
||||
style={{ backgroundImage: `url('${item.thumbnail}')` }}
|
||||
></div>
|
||||
<div
|
||||
className="news-layer-image"
|
||||
style={{ backgroundImage: `url('${item.thumbnail}')` }}
|
||||
></div>
|
||||
<div
|
||||
className="news-layer-image"
|
||||
style={{ backgroundImage: `url('${item.thumbnail}')` }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="news-content">
|
||||
<div className="list">
|
||||
<span>Comment ({item.comments})</span>
|
||||
<span>_ {item.date}</span>
|
||||
</div>
|
||||
<h3>
|
||||
<Link href={item.link}>{item.title}</Link>
|
||||
</h3>
|
||||
<div className="news-bottom">
|
||||
<div className="info-item">
|
||||
<img src={item.author.avatar} alt="img" />
|
||||
<span>By {item.author.name}</span>
|
||||
</div>
|
||||
<Link href={item.link} className="link-btn">
|
||||
View Articles<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutNews;
|
||||
65
app/components/about/Campus.tsx
Normal file
65
app/components/about/Campus.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import Link from "next/link";
|
||||
|
||||
const CENTERS = [
|
||||
{
|
||||
tag: "Biosciences",
|
||||
tagColor: "blue",
|
||||
title: "Institut Pasteur Collaborative Lab",
|
||||
desc: "A premier center focusing on immunology, genetics, and infectious diseases.",
|
||||
img: "https://storage.googleapis.com/uxpilot-auth.appspot.com/115ee2f067-72629210549870cf0d35.png",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
tag: "Humanities",
|
||||
tagColor: "yellow",
|
||||
title: "Center for European Studies",
|
||||
desc: "Housing over 2 million volumes and dedicated to historical and sociological research.",
|
||||
img: "https://storage.googleapis.com/uxpilot-auth.appspot.com/c11358a8da-a7b331f85d1fbd27c851.png",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
tag: "Technology",
|
||||
tagColor: "green",
|
||||
title: "AI & Robotics Institute",
|
||||
desc: "Pioneering developments in machine learning, automation, and computational science.",
|
||||
img: "https://storage.googleapis.com/uxpilot-auth.appspot.com/97fca8b57f-238aa78a799f22cf1cd1.png",
|
||||
href: "#",
|
||||
},
|
||||
];
|
||||
|
||||
const Campus = () => {
|
||||
return (
|
||||
<section id="campus" className="about-campus">
|
||||
<div className="container">
|
||||
<div className="about-campus__header text-center">
|
||||
<h2 className="about-campus__title">Campus & Research Centers</h2>
|
||||
<p className="about-campus__subtitle">
|
||||
State-of-the-art facilities nestled in the historic Latin Quarter, designed to foster innovation and collaboration.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="about-campus__grid">
|
||||
{CENTERS.map((center, i) => (
|
||||
<div key={i} className="about-campus__card">
|
||||
<div className="about-campus__img-wrap">
|
||||
<img src={center.img} alt={center.title} className="about-campus__img" />
|
||||
</div>
|
||||
<div className="about-campus__body">
|
||||
<span className={`about-campus__tag about-campus__tag--${center.tagColor}`}>
|
||||
{center.tag}
|
||||
</span>
|
||||
<h3 className="about-campus__card-title">{center.title}</h3>
|
||||
<p className="about-campus__card-desc">{center.desc}</p>
|
||||
<Link href={center.href} className="about-campus__link">
|
||||
Explore Facility <i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Campus;
|
||||
74
app/components/about/HeroSection.tsx
Normal file
74
app/components/about/HeroSection.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { AboutData } from "@/app/about/types";
|
||||
import { getCmsImageUrl } from "@/utils/image";
|
||||
import Link from "next/link";
|
||||
|
||||
interface HeroSectionProps {
|
||||
data?: AboutData | null;
|
||||
}
|
||||
|
||||
const HeroSection = ({ data }: HeroSectionProps) => {
|
||||
const title = data?.hero?.title || "A Legacy of Liberal Arts & Research";
|
||||
const backgroundImage = data?.hero?.backgroundImage
|
||||
? getCmsImageUrl(data.hero.backgroundImage)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<section
|
||||
id="about-hero"
|
||||
className="about-hero fix bg-cover"
|
||||
style={backgroundImage ? { backgroundImage: `url('${backgroundImage}')` } : undefined}
|
||||
>
|
||||
<div className="container">
|
||||
<div className="row align-items-center">
|
||||
{/* Left: Text */}
|
||||
<div className="col-lg-6">
|
||||
<div className="about-hero__content">
|
||||
<div className="about-hero__badge">
|
||||
<span className="about-hero__badge-line"></span>
|
||||
<span className="about-hero__badge-text">Our Identity</span>
|
||||
</div>
|
||||
<h1 className="about-hero__title"
|
||||
dangerouslySetInnerHTML={{ __html: title }}
|
||||
/>
|
||||
<p className="about-hero__desc">
|
||||
Founded in the heart of Paris, Université Libérale is dedicated to fostering
|
||||
critical thinking, interdisciplinary innovation, and global understanding through
|
||||
a rigorous liberal arts curriculum and world-class research initiatives.
|
||||
</p>
|
||||
<div className="about-hero__actions">
|
||||
<button className="about-hero__btn">
|
||||
Discover Our History
|
||||
<i className="fa-solid fa-arrow-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right: Image */}
|
||||
<div className="col-lg-6">
|
||||
<div className="about-hero__image-wrap">
|
||||
<img
|
||||
src={data?.intro?.image
|
||||
? getCmsImageUrl(data.intro.image)
|
||||
: "https://storage.googleapis.com/uxpilot-auth.appspot.com/e0291249ca-9b14cf509f6076b406c0.png"}
|
||||
alt="University campus"
|
||||
className="about-hero__image"
|
||||
/>
|
||||
<div className="about-hero__badge-card">
|
||||
<div className="about-hero__badge-icon">
|
||||
<i className="fa-solid fa-award"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="about-hero__badge-value">Top 50</h4>
|
||||
<p className="about-hero__badge-label">Global Research Ranking</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroSection;
|
||||
39
app/components/about/HistoryTimeline.tsx
Normal file
39
app/components/about/HistoryTimeline.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
const TIMELINE = [
|
||||
{ year: "1895", title: "Foundation", desc: "Established as an independent institute for liberal studies by a group of visionary scholars.", side: "left" },
|
||||
{ year: "1945", title: "Post-War Expansion", desc: "Expanded faculties to include modern sciences and established the first dedicated research hub.", side: "right" },
|
||||
{ year: "1982", title: "Global Partnerships", desc: "Initiated formal exchange programs and research partnerships with leading universities worldwide.", side: "left" },
|
||||
{ year: "2020", title: "Modern Research Era", desc: "Inauguration of the new interdisciplinary research center, focusing on sustainable global development.", side: "right" },
|
||||
];
|
||||
|
||||
const HistoryTimeline = () => {
|
||||
return (
|
||||
<section id="history-timeline" className="about-timeline">
|
||||
<div className="container">
|
||||
<div className="about-timeline__header text-center">
|
||||
<h2 className="about-timeline__title">Our History</h2>
|
||||
<p className="about-timeline__subtitle">A legacy of academic excellence spanning over a century.</p>
|
||||
</div>
|
||||
|
||||
<div className="about-timeline__track">
|
||||
<div className="about-timeline__line"></div>
|
||||
|
||||
{TIMELINE.map((item, i) => (
|
||||
<div key={i} className={`about-timeline__item about-timeline__item--${item.side}`}>
|
||||
<div className="about-timeline__content">
|
||||
<h3 className="about-timeline__year">{item.year}</h3>
|
||||
<h4 className="about-timeline__event">{item.title}</h4>
|
||||
<p className="about-timeline__desc">{item.desc}</p>
|
||||
</div>
|
||||
<div className="about-timeline__dot-wrap">
|
||||
<div className="about-timeline__dot"></div>
|
||||
</div>
|
||||
<div className="about-timeline__spacer"></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HistoryTimeline;
|
||||
66
app/components/about/LeaderShip_Broad.tsx
Normal file
66
app/components/about/LeaderShip_Broad.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import Link from "next/link";
|
||||
|
||||
const LEADERS = [
|
||||
{
|
||||
name: "Dr. Eleanor Laurent",
|
||||
role: "President",
|
||||
img: "https://storage.googleapis.com/uxpilot-auth.appspot.com/8ce6757572-cd9d4e986dee9e71d10c.png",
|
||||
},
|
||||
{
|
||||
name: "Prof. Marcus Dubois",
|
||||
role: "Dean of Humanities",
|
||||
img: "https://storage.googleapis.com/uxpilot-auth.appspot.com/3aae15d87b-020f60df05ac2c52a087.png",
|
||||
},
|
||||
{
|
||||
name: "Dr. Sophie Martin",
|
||||
role: "Dean of Research",
|
||||
img: "https://storage.googleapis.com/uxpilot-auth.appspot.com/3fc05a202c-26e5f00c35a829b5462d.png",
|
||||
},
|
||||
{
|
||||
name: "Prof. Jean-Paul Roux",
|
||||
role: "Provost",
|
||||
img: "https://storage.googleapis.com/uxpilot-auth.appspot.com/3aae15d87b-c36f00cff7803c4209d4.png",
|
||||
},
|
||||
];
|
||||
|
||||
const LeadershipBoard = () => {
|
||||
return (
|
||||
<section id="leadership-board" className="about-leadership">
|
||||
<div className="container">
|
||||
<div className="about-leadership__header text-center">
|
||||
<div className="about-mission__badge">
|
||||
<span className="about-mission__badge-line"></span>
|
||||
<span className="about-mission__badge-text">University Leadership</span>
|
||||
<span className="about-mission__badge-line"></span>
|
||||
</div>
|
||||
<h2 className="about-leadership__title">Meet Our Leaders</h2>
|
||||
<p className="about-leadership__subtitle">Guiding our academic vision and institutional strategy.</p>
|
||||
</div>
|
||||
|
||||
<div className="about-leadership__grid">
|
||||
{LEADERS.map((leader, i) => (
|
||||
<div key={i} className="about-leadership__card">
|
||||
<div className="about-leadership__photo-wrap">
|
||||
<img src={leader.img} alt={leader.name} className="about-leadership__photo" />
|
||||
</div>
|
||||
<div className="about-leadership__info">
|
||||
<h3 className="about-leadership__name">{leader.name}</h3>
|
||||
<p className="about-leadership__role">{leader.role}</p>
|
||||
<div className="about-leadership__socials">
|
||||
<Link href="#" className="about-leadership__social-link">
|
||||
<i className="fa-brands fa-linkedin"></i>
|
||||
</Link>
|
||||
<Link href="#" className="about-leadership__social-link">
|
||||
<i className="fa-solid fa-envelope"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default LeadershipBoard;
|
||||
73
app/components/about/LeaderShip_Message.tsx
Normal file
73
app/components/about/LeaderShip_Message.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import Link from "next/link";
|
||||
|
||||
const LeadershipMessage = () => {
|
||||
return (
|
||||
<section id="leadership-message" className="about-message">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
{/* Main content */}
|
||||
<div className="col-lg-8">
|
||||
<div className="about-message__header">
|
||||
<h2 className="about-message__title">A Message from the President</h2>
|
||||
<div className="about-message__divider"></div>
|
||||
</div>
|
||||
<div className="about-message__body">
|
||||
<p className="about-message__quote">
|
||||
"Research is not just about discovery; it is about responsibility. As a premier institution in Paris, we carry the torch of enlightenment into the 21st century."
|
||||
</p>
|
||||
<p>
|
||||
Welcome to Paris Research University. For decades, our halls have echoed with the profound debates of brilliant minds and the quiet hum of groundbreaking laboratories. We stand at the intersection of history and the future, leveraging our rich heritage to propel innovation that addresses the world's most pressing challenges.
|
||||
</p>
|
||||
<p>
|
||||
Our commitment is unwavering: to foster an inclusive, vibrant academic community where interdisciplinary collaboration thrives. We invite you to explore our centers, engage with our faculty, and join us in our relentless pursuit of knowledge.
|
||||
</p>
|
||||
</div>
|
||||
<div className="about-message__author">
|
||||
<div className="about-message__avatar">
|
||||
<img src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-4.jpg" alt="President" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="about-message__author-name">Dr. Jean-UX Pilot Laurent</h4>
|
||||
<p className="about-message__author-role">President & Vice-Chancellor</p>
|
||||
</div>
|
||||
<i className="fa-solid fa-quote-right about-message__quote-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div className="col-lg-4">
|
||||
<div className="about-message__sidebar">
|
||||
<div className="about-message__sidebar-card about-message__sidebar-card--primary">
|
||||
<h3>Accreditation & Standards</h3>
|
||||
<p>Learn about our rigorous academic standards and global recognitions.</p>
|
||||
<Link href="/accreditation" className="about-message__sidebar-link">
|
||||
View Credentials <i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="about-message__sidebar-card">
|
||||
<div className="about-message__sidebar-icon">
|
||||
<i className="fa-solid fa-handshake"></i>
|
||||
</div>
|
||||
<h3>Global Partnerships</h3>
|
||||
<p>Explore our network of industry and academic collaborators.</p>
|
||||
<Link href="/partnerships" className="about-message__sidebar-text-link">
|
||||
Discover Network <i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="about-message__sidebar-card">
|
||||
<h3>Have Questions?</h3>
|
||||
<Link href="/contact" className="about-message__sidebar-outline-link">
|
||||
Contact Administration
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default LeadershipMessage;
|
||||
51
app/components/about/Mission.tsx
Normal file
51
app/components/about/Mission.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
const VALUES = [
|
||||
{
|
||||
icon: "fa-solid fa-book-open",
|
||||
title: "Liberal Arts Foundation",
|
||||
desc: "Providing a broad intellectual foundation that encourages critical thinking, creativity, and the ability to adapt to a rapidly changing world.",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-microscope",
|
||||
title: "Research Excellence",
|
||||
desc: "Fostering a culture of rigorous inquiry and innovation, supporting faculty and students in pushing the boundaries of knowledge.",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-globe",
|
||||
title: "Global Perspective",
|
||||
desc: "Cultivating an inclusive environment that values diverse perspectives and prepares students to engage with complex global challenges.",
|
||||
},
|
||||
];
|
||||
|
||||
const Mission = () => {
|
||||
return (
|
||||
<section id="mission-values" className="about-mission">
|
||||
<div className="container">
|
||||
<div className="about-mission__header text-center">
|
||||
<div className="about-mission__badge">
|
||||
<span className="about-mission__badge-line"></span>
|
||||
<span className="about-mission__badge-text">Core Principles</span>
|
||||
<span className="about-mission__badge-line"></span>
|
||||
</div>
|
||||
<h2 className="about-mission__title">Our Mission & Values</h2>
|
||||
<p className="about-mission__subtitle">
|
||||
We are committed to advancing human knowledge and cultivating responsible global citizens through transformative education.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="about-mission__grid">
|
||||
{VALUES.map((item, i) => (
|
||||
<div key={i} className="about-mission__card">
|
||||
<div className="about-mission__icon-wrap">
|
||||
<i className={item.icon}></i>
|
||||
</div>
|
||||
<h3 className="about-mission__card-title">{item.title}</h3>
|
||||
<p className="about-mission__card-desc">{item.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Mission;
|
||||
65
app/components/about/WhyParis.tsx
Normal file
65
app/components/about/WhyParis.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
const FEATURES = [
|
||||
"Access to world-renowned museums, archives, and libraries.",
|
||||
"A hub for international organizations and global policy.",
|
||||
"A vibrant cultural ecosystem that enriches the liberal arts experience.",
|
||||
];
|
||||
|
||||
const IMAGES = [
|
||||
{ src: "https://storage.googleapis.com/uxpilot-auth.appspot.com/4df3620db3-dda28233c91d6369d039.png", alt: "Parisian cafe and street", tall: false },
|
||||
{ src: "https://storage.googleapis.com/uxpilot-auth.appspot.com/a45c3de13a-8173142c33595269388d.png", alt: "Students in Parisian library", tall: true },
|
||||
{ src: "https://storage.googleapis.com/uxpilot-auth.appspot.com/fe39e27ab6-40f9c9b4851f3b8176da.png", alt: "Seine river with historic bridges", tall: true },
|
||||
{ src: "https://storage.googleapis.com/uxpilot-auth.appspot.com/cb66207ea0-16795a67db08ef0e6f8c.png", alt: "Modern research facility", tall: false },
|
||||
];
|
||||
|
||||
const WhyParis = () => {
|
||||
return (
|
||||
<section id="why-paris" className="why-paris">
|
||||
<div className="container">
|
||||
<div className="row align-items-center">
|
||||
{/* Left: Image grid */}
|
||||
<div className="col-lg-6 order-lg-1 order-2">
|
||||
<div className="why-paris__image-grid">
|
||||
<div className="why-paris__image-col">
|
||||
<img src={IMAGES[0].src} alt={IMAGES[0].alt} className="why-paris__img why-paris__img--short" />
|
||||
<img src={IMAGES[1].src} alt={IMAGES[1].alt} className="why-paris__img why-paris__img--tall" />
|
||||
</div>
|
||||
<div className="why-paris__image-col why-paris__image-col--offset">
|
||||
<img src={IMAGES[2].src} alt={IMAGES[2].alt} className="why-paris__img why-paris__img--tall" />
|
||||
<img src={IMAGES[3].src} alt={IMAGES[3].alt} className="why-paris__img why-paris__img--short" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right: Text */}
|
||||
<div className="col-lg-6 order-lg-2 order-1">
|
||||
<div className="why-paris__content">
|
||||
<div className="about-hero__badge">
|
||||
<span className="about-hero__badge-line"></span>
|
||||
<span className="about-hero__badge-text">Our Location</span>
|
||||
</div>
|
||||
<h2 className="why-paris__title">Why Paris?</h2>
|
||||
<p className="why-paris__desc">
|
||||
Paris is not just a backdrop; it is our extended campus. As a historic center
|
||||
of intellectual thought, art, and scientific discovery, the city offers
|
||||
unparalleled opportunities for our students and researchers.
|
||||
</p>
|
||||
<ul className="why-paris__list">
|
||||
{FEATURES.map((item, i) => (
|
||||
<li key={i} className="why-paris__list-item">
|
||||
<span className="why-paris__check">
|
||||
<i className="fa-solid fa-check"></i>
|
||||
</span>
|
||||
<span>{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<button className="why-paris__btn">Explore Campus Life</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default WhyParis;
|
||||
902
app/components/about/about.css
Normal file
902
app/components/about/about.css
Normal file
@@ -0,0 +1,902 @@
|
||||
/* ============================================================
|
||||
ABOUT PAGE
|
||||
============================================================ */
|
||||
|
||||
.about-hero {
|
||||
padding: 80px 0;
|
||||
background-color: #f8fbff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.about-hero__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.about-hero__badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.about-hero__badge-line {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2px;
|
||||
background: #1b254b;
|
||||
}
|
||||
|
||||
.about-hero__badge-text {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.about-hero__title {
|
||||
font-size: clamp(2rem, 4vw, 3.5rem);
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
line-height: 1.15;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about-hero__title span {
|
||||
color: var(--theme, #E13833);
|
||||
}
|
||||
|
||||
.about-hero__desc {
|
||||
font-size: 1.05rem;
|
||||
color: #6b7280;
|
||||
line-height: 1.7;
|
||||
max-width: 36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about-hero__actions {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.about-hero__btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.875rem 2rem;
|
||||
background-color: #1b254b;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
border-radius: 0.375rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1);
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.about-hero__btn:hover {
|
||||
background-color: #151c3a;
|
||||
}
|
||||
|
||||
/* Image side */
|
||||
.about-hero__image-wrap {
|
||||
position: relative;
|
||||
border-radius: 1rem;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.about-hero__image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 1rem;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.12);
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Badge card overlay */
|
||||
.about-hero__badge-card {
|
||||
position: absolute;
|
||||
bottom: -1.5rem;
|
||||
left: -1.5rem;
|
||||
background: #ffffff;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.about-hero__badge-card {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.about-hero__badge-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background: #f8fbff;
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.25rem;
|
||||
color: #1b254b;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.about-hero__badge-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about-hero__badge-label {
|
||||
font-size: 0.8rem;
|
||||
color: #6b7280;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.about-hero {
|
||||
padding: 80px 0 60px;
|
||||
}
|
||||
|
||||
.about-hero__image-wrap {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Mission & Values
|
||||
------------------------------------------------------------ */
|
||||
.about-mission {
|
||||
padding: 80px 0;
|
||||
background-color: #f8f8f9;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.about-mission__header {
|
||||
max-width: 48rem;
|
||||
margin: 0 auto 4rem;
|
||||
}
|
||||
|
||||
.about-mission__badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.about-mission__badge-line {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2px;
|
||||
background: #E13833;
|
||||
}
|
||||
|
||||
.about-mission__badge-text {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.about-mission__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.25rem);
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.about-mission__subtitle {
|
||||
font-size: 1.05rem;
|
||||
color: #6b7280;
|
||||
line-height: 1.7;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about-mission__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.about-mission__grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.about-mission__card {
|
||||
background: #ffffff;
|
||||
padding: 2rem;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
||||
transition: box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.about-mission__card:hover {
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.about-mission__icon-wrap {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
background: #f8fbff;
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.25rem;
|
||||
color: #1b254b;
|
||||
margin-bottom: 1.5rem;
|
||||
border-top: 4px solid transparent;
|
||||
transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.about-mission__card:hover .about-mission__icon-wrap {
|
||||
background-color: #1b254b;
|
||||
color: #ffffff;
|
||||
border-top-color: #E13833;
|
||||
}
|
||||
|
||||
.about-mission__card-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-mission__card-desc {
|
||||
font-size: 0.95rem;
|
||||
color: #6b7280;
|
||||
line-height: 1.7;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Why Paris
|
||||
------------------------------------------------------------ */
|
||||
.why-paris {
|
||||
padding: 80px 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.why-paris__image-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.why-paris__image-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.why-paris__image-col--offset {
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.why-paris__img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.why-paris__img--short { height: 12rem; }
|
||||
.why-paris__img--tall { height: 16rem; }
|
||||
|
||||
.why-paris__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.why-paris__content {
|
||||
padding-left: 0;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.why-paris__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.25rem);
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.why-paris__desc {
|
||||
font-size: 1.05rem;
|
||||
color: #6b7280;
|
||||
line-height: 1.7;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.why-paris__list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.why-paris__list-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
color: #1b254b;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.why-paris__check {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
border-radius: 50%;
|
||||
background: #f8fbff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #1b254b;
|
||||
font-size: 0.65rem;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.why-paris__btn {
|
||||
display: inline-block;
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.625rem 1.5rem;
|
||||
background: #f8fbff;
|
||||
color: #1b254b;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.why-paris__btn:hover {
|
||||
background-color: #e5e7eb;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Leadership Message
|
||||
------------------------------------------------------------ */
|
||||
.about-message {
|
||||
padding: 80px 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.about-message__header {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.about-message__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.5rem);
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.about-message__divider {
|
||||
width: 5rem;
|
||||
height: 4px;
|
||||
background: #E13833;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.about-message__body p {
|
||||
color: #6b7280;
|
||||
line-height: 1.8;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.about-message__quote {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
color: #1b254b !important;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.about-message__author {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
margin-top: 2rem;
|
||||
padding: 1.5rem;
|
||||
background: #f8f8f9;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.about-message__avatar {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 2px solid #E13833;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.about-message__avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.about-message__author-name {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin: 0 0 0.25rem;
|
||||
}
|
||||
|
||||
.about-message__author-role {
|
||||
font-size: 0.875rem;
|
||||
color: #E13833;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about-message__quote-icon {
|
||||
font-size: 3rem;
|
||||
color: #1b254b;
|
||||
opacity: 0.15;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.about-message__sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
position: sticky;
|
||||
top: 7rem;
|
||||
}
|
||||
|
||||
.about-message__sidebar-card {
|
||||
background: #f8f8f9;
|
||||
padding: 2rem;
|
||||
border-radius: 1.5rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.about-message__sidebar-card h3 {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-message__sidebar-card p {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.about-message__sidebar-card--primary {
|
||||
background: #1b254b;
|
||||
}
|
||||
|
||||
.about-message__sidebar-card--primary h3,
|
||||
.about-message__sidebar-card--primary p {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.about-message__sidebar-card--primary p {
|
||||
color: rgba(255,255,255,0.75);
|
||||
}
|
||||
|
||||
.about-message__sidebar-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
color: #1b254b;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 999px;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.about-message__sidebar-link:hover { background: #f3f4f6; }
|
||||
|
||||
.about-message__sidebar-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background: #ffffff;
|
||||
border-radius: 0.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.25rem;
|
||||
color: #1b254b;
|
||||
margin-bottom: 1rem;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.about-message__sidebar-text-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: #1b254b;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.about-message__sidebar-text-link:hover { text-decoration: underline; }
|
||||
|
||||
.about-message__sidebar-outline-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
border: 2px solid #1b254b;
|
||||
color: #1b254b;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 999px;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.about-message__sidebar-outline-link:hover {
|
||||
background: #1b254b;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Leadership Board
|
||||
------------------------------------------------------------ */
|
||||
.about-leadership {
|
||||
padding: 80px 0;
|
||||
background: #f8f8f9;
|
||||
}
|
||||
|
||||
.about-leadership__header {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.about-leadership__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.25rem);
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-leadership__subtitle {
|
||||
color: #6b7280;
|
||||
font-size: 1.05rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about-leadership__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.about-leadership__grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
|
||||
@media (max-width: 575px) {
|
||||
.about-leadership__grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.about-leadership__card {
|
||||
background: #ffffff;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.about-leadership__card:hover { box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
|
||||
|
||||
.about-leadership__photo-wrap {
|
||||
height: 16rem;
|
||||
overflow: hidden;
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
.about-leadership__photo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.about-leadership__card:hover .about-leadership__photo { transform: scale(1.05); }
|
||||
|
||||
.about-leadership__info {
|
||||
padding: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.about-leadership__name {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.about-leadership__role {
|
||||
font-size: 0.875rem;
|
||||
color: #E13833;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-leadership__socials {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.about-leadership__social-link {
|
||||
color: #6b7280;
|
||||
font-size: 1rem;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.about-leadership__social-link:hover { color: #1b254b; }
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Campus
|
||||
------------------------------------------------------------ */
|
||||
.about-campus {
|
||||
padding: 80px 0;
|
||||
background: #f8f8f9;
|
||||
}
|
||||
|
||||
.about-campus__header {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.about-campus__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.25rem);
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-campus__subtitle {
|
||||
color: #6b7280;
|
||||
max-width: 40rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.about-campus__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.about-campus__grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.about-campus__card {
|
||||
background: #ffffff;
|
||||
border-radius: 1.5rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.about-campus__card:hover { box-shadow: 0 12px 32px rgba(0,0,0,0.1); }
|
||||
|
||||
.about-campus__img-wrap {
|
||||
height: 12rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.about-campus__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.about-campus__card:hover .about-campus__img { transform: scale(1.05); }
|
||||
|
||||
.about-campus__body {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.about-campus__tag {
|
||||
display: inline-block;
|
||||
padding: 0.2rem 0.75rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.about-campus__tag--blue { background: #eff6ff; color: #1b254b; }
|
||||
.about-campus__tag--yellow { background: #fefce8; color: #854d0e; }
|
||||
.about-campus__tag--green { background: #f0fdf4; color: #166534; }
|
||||
|
||||
.about-campus__card-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-campus__card-desc {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.about-campus__link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: #1b254b;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
text-decoration: none;
|
||||
transition: gap 0.2s;
|
||||
}
|
||||
|
||||
.about-campus__link:hover { gap: 0.75rem; }
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
History Timeline
|
||||
------------------------------------------------------------ */
|
||||
.about-timeline {
|
||||
padding: 80px 0;
|
||||
background: #1b254b;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.about-timeline__header { margin-bottom: 3rem; }
|
||||
|
||||
.about-timeline__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.5rem);
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-timeline__subtitle { color: rgba(255,255,255,0.65); font-size: 1rem; margin: 0; }
|
||||
|
||||
.about-timeline__track {
|
||||
max-width: 44rem;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
/* Vertical line chạy giữa track */
|
||||
.about-timeline__line {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
margin-left: -1px;
|
||||
background: rgba(100,160,255,0.3);
|
||||
}
|
||||
|
||||
.about-timeline__item {
|
||||
display: flex;
|
||||
margin-bottom: 3.5rem;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.about-timeline__item:last-child { margin-bottom: 0; }
|
||||
|
||||
/* Content chiếm nửa trái hoặc phải */
|
||||
.about-timeline__content {
|
||||
width: calc(50% - 1.5rem);
|
||||
}
|
||||
|
||||
/* Dot nằm absolute giữa line */
|
||||
.about-timeline__dot-wrap {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0.3rem;
|
||||
transform: translateX(-50%);
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Spacer chiếm nửa còn lại */
|
||||
.about-timeline__spacer {
|
||||
width: calc(50% - 1.5rem);
|
||||
}
|
||||
|
||||
/* Left: content bên trái, text align right */
|
||||
.about-timeline__item--left .about-timeline__content {
|
||||
text-align: right;
|
||||
order: 1;
|
||||
margin-right: 3rem;
|
||||
}
|
||||
.about-timeline__item--left .about-timeline__dot-wrap { order: 2; }
|
||||
.about-timeline__item--left .about-timeline__spacer { order: 3; }
|
||||
|
||||
/* Right: spacer bên trái, content bên phải */
|
||||
.about-timeline__item--right .about-timeline__spacer { order: 1; }
|
||||
.about-timeline__item--right .about-timeline__dot-wrap { order: 2; }
|
||||
.about-timeline__item--right .about-timeline__content {
|
||||
text-align: left;
|
||||
order: 3;
|
||||
margin-left: 3rem;
|
||||
}
|
||||
|
||||
.about-timeline__dot {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
border: 2px solid #74b3ff;
|
||||
box-shadow: 0 0 0 4px rgba(116,179,255,0.15);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.about-timeline__year {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 0.25rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.about-timeline__event {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: #74b3ff;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.about-timeline__desc {
|
||||
font-size: 0.875rem;
|
||||
color: rgba(255,255,255,0.65);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
max-width: 18rem;
|
||||
}
|
||||
|
||||
.about-timeline__item--left .about-timeline__desc { margin-left: auto; }
|
||||
.about-timeline__item--right .about-timeline__desc { margin-right: auto; }
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.about-timeline__line { left: 0.75rem; }
|
||||
.about-timeline__item { flex-direction: column; align-items: flex-start; padding-left: 2.5rem; }
|
||||
.about-timeline__item--left .about-timeline__content,
|
||||
.about-timeline__item--right .about-timeline__content { text-align: left; padding: 0; order: 2; }
|
||||
.about-timeline__item--left .about-timeline__desc,
|
||||
.about-timeline__item--right .about-timeline__desc { margin: 0; max-width: 100%; }
|
||||
.about-timeline__dot-wrap { position: absolute; left: 0; top: 0.25rem; order: 1; }
|
||||
.about-timeline__spacer { display: none; }
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export { default as AboutHero } from './AboutHero';
|
||||
export { default as AboutIntro } from './AboutIntro';
|
||||
export { default as AboutMission } from './AboutMission';
|
||||
export { default as AboutFeatures } from './AboutFeatures';
|
||||
export { default as AboutNews } from './AboutNews';
|
||||
@@ -1,47 +0,0 @@
|
||||
interface AchievementsProps {
|
||||
data: {
|
||||
heading: string;
|
||||
subheading: string;
|
||||
items: {
|
||||
value: string;
|
||||
suffix: string;
|
||||
label: string;
|
||||
description: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
const Achievements = ({ data }: AchievementsProps) => {
|
||||
return (
|
||||
<section className="counter-section section-padding pb-0 fix bg-cover" style={{ backgroundImage: "url('/assets/img/home-1/feature/bg-2.jpg')" }}>
|
||||
<div className="shape">
|
||||
<img src="/assets/img/home-1/feature/shape-2.png" alt="img" />
|
||||
</div>
|
||||
<div className="container">
|
||||
<div className="section-title text-center">
|
||||
<span className="sub-title bg-2 wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="text-white split-text-right split-text-in-right">
|
||||
{data.heading}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="counter-wrapper">
|
||||
<div className="container">
|
||||
<div className="counter-main-item">
|
||||
{data.items.map((item, index) => (
|
||||
<div key={index} className={`counter-item ${index < 3 ? 'style-2' : ''}`}>
|
||||
<h2><span className="odometer" data-count={item.value}>00</span>{item.suffix}</h2>
|
||||
<h5>{item.label}</h5>
|
||||
<p>
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Achievements;
|
||||
@@ -1,116 +0,0 @@
|
||||
import { getCmsImageUrl } from '@/utils/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
interface BlogPreviewProps {
|
||||
data: {
|
||||
heading: string;
|
||||
subheading: string;
|
||||
ctaButton: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
items: {
|
||||
title: string;
|
||||
excerpt: string;
|
||||
category: string;
|
||||
date: string;
|
||||
author: {
|
||||
name: string;
|
||||
avatar: string;
|
||||
};
|
||||
comments: number;
|
||||
link: string;
|
||||
thumbnail: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
const BlogPreview = ({ data }: BlogPreviewProps) => {
|
||||
const formatDate = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('en-US', { day: 'numeric', month: 'long', year: 'numeric' });
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="news-section section-padding fix">
|
||||
<div className="container">
|
||||
<div className="section-title-area">
|
||||
<div className="section-title">
|
||||
<span className="sub-title wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">
|
||||
{data.heading}
|
||||
</h2>
|
||||
</div>
|
||||
<Link href={data.ctaButton.href} className="theme-btn wow fadeInUp" data-wow-delay=".3s">
|
||||
{data.ctaButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="row">
|
||||
{data.items.map((item, index) => {
|
||||
const thumbUrl = getCmsImageUrl(item.thumbnail);
|
||||
return (
|
||||
<div key={index} className="col-xl-4 col-lg-6 col-md-6 wow fadeInUp" data-wow-delay={`.${(index + 1) * 2 + 1}s`}>
|
||||
<div className="news-card-item">
|
||||
<div className="news-image">
|
||||
<img
|
||||
src={thumbUrl}
|
||||
alt="img"
|
||||
style={{
|
||||
width: '419px',
|
||||
height: '312px',
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
/>
|
||||
<span>{item.category}</span>
|
||||
<div className="news-layer-wrapper">
|
||||
<div className="news-layer-image" style={{ backgroundImage: `url('${thumbUrl}')`, width: '419px', height: '312px' }}></div>
|
||||
<div className="news-layer-image" style={{ backgroundImage: `url('${thumbUrl}')`, width: '419px', height: '312px' }}></div>
|
||||
<div className="news-layer-image" style={{ backgroundImage: `url('${thumbUrl}')`, width: '419px', height: '312px' }}></div>
|
||||
<div className="news-layer-image" style={{ backgroundImage: `url('${thumbUrl}')`, width: '419px', height: '312px' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="news-content">
|
||||
<div className="list">
|
||||
<span>Comment ({item.comments.toString().padStart(2, '0')})</span>
|
||||
<span>_ {formatDate(item.date)}</span>
|
||||
</div>
|
||||
<h3>
|
||||
<Link href={item.link}>
|
||||
{item.title}
|
||||
</Link>
|
||||
</h3>
|
||||
<div className="news-bottom">
|
||||
<div className="info-item">
|
||||
<div
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
backgroundColor: '#d1d5db',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: '14px',
|
||||
fontWeight: 'bold',
|
||||
color: '#374151',
|
||||
marginRight: '10px'
|
||||
}}
|
||||
>
|
||||
{item.author.name.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<span>By {item.author.name}</span>
|
||||
</div>
|
||||
<Link href={item.link} className="link-btn">View Articles<i className="fa-solid fa-arrow-right"></i></Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPreview;
|
||||
@@ -1,83 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
interface FAQSectionProps {
|
||||
data: {
|
||||
heading: string;
|
||||
subheading: string;
|
||||
description: string;
|
||||
ctaButton: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
items: {
|
||||
question: string;
|
||||
answer: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
const FAQSection = ({ data }: FAQSectionProps) => {
|
||||
return (
|
||||
<section className="faq-section section-padding fix">
|
||||
<div className="container">
|
||||
<div className="faq-wrapper">
|
||||
<div className="row g-4">
|
||||
<div className="col-lg-5">
|
||||
<div className="faq-content">
|
||||
<div className="section-title mb-0">
|
||||
<span className="sub-title wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">
|
||||
{data.heading}
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text">
|
||||
{data.description}
|
||||
</p>
|
||||
<Link href={data.ctaButton.href} className="theme-btn">
|
||||
{data.ctaButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-7">
|
||||
<div className="faq-items">
|
||||
<div className="accordion" id="accordionExample">
|
||||
{data.items.map((item, index) => (
|
||||
<div key={index} className="accordion-item wow fadeInUp" data-wow-delay={`.${(index + 1) * 2}s`}>
|
||||
<h5 className="accordion-header" id={`heading${index}`}>
|
||||
<button
|
||||
className="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target={`#collapse${index}`}
|
||||
aria-expanded="false"
|
||||
aria-controls={`collapse${index}`}
|
||||
>
|
||||
{item.question}
|
||||
</button>
|
||||
</h5>
|
||||
<div
|
||||
id={`collapse${index}`}
|
||||
className="accordion-collapse collapse"
|
||||
aria-labelledby={`heading${index}`}
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div className="accordion-body">
|
||||
<p>
|
||||
{item.answer}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default FAQSection;
|
||||
@@ -1,141 +1,46 @@
|
||||
import { getCmsImageUrl } from '@/utils/image';
|
||||
import Link from 'next/link';
|
||||
import Link from "next/link";
|
||||
|
||||
interface HeroSlide {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
description: string;
|
||||
primaryButton: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
secondaryButton: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
heroImage?: string;
|
||||
videoUrl: string;
|
||||
}
|
||||
const HeroSection = () => {
|
||||
return (
|
||||
<section id="hero-banner" className="hero-home">
|
||||
<div className="hero-home__overlay">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1541339907198-e08756dedf3f?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80"
|
||||
alt="Paris University Campus"
|
||||
className="hero-home__bg-img"
|
||||
/>
|
||||
<div className="hero-home__gradient" />
|
||||
</div>
|
||||
|
||||
interface HeroSectionProps {
|
||||
data: {
|
||||
backgroundImage: string;
|
||||
// Optional multi-slide support from CMS
|
||||
slides?: HeroSlide[];
|
||||
// Legacy single-slide fields (fallback)
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
description?: string;
|
||||
primaryButton?: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
secondaryButton?: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
heroImage?: string;
|
||||
videoUrl?: string;
|
||||
};
|
||||
}
|
||||
<div className="hero-home__container">
|
||||
<div className="hero-home__content">
|
||||
<div className="hero-home__badge">
|
||||
<span className="hero-home__badge-dot" />
|
||||
<span className="hero-home__badge-text">Leading Research Institution</span>
|
||||
</div>
|
||||
|
||||
const HeroSection = ({ data }: HeroSectionProps) => {
|
||||
const slides: HeroSlide[] =
|
||||
(data.slides && data.slides.length > 0)
|
||||
? data.slides
|
||||
: [{
|
||||
title: data.title || '',
|
||||
subtitle: data.subtitle || '',
|
||||
description: data.description || '',
|
||||
primaryButton: data.primaryButton || { label: '', href: '#' },
|
||||
secondaryButton: data.secondaryButton || { label: '', href: '#' },
|
||||
heroImage: data.heroImage,
|
||||
videoUrl: data.videoUrl || '',
|
||||
}];
|
||||
<h1 className="hero-home__title">
|
||||
Advancing Knowledge in the Heart of Paris
|
||||
</h1>
|
||||
|
||||
const firstSlide = slides[0];
|
||||
<p className="hero-home__desc">
|
||||
A premier liberal arts and research university dedicated to fostering
|
||||
interdisciplinary innovation, global partnerships, and academic excellence.
|
||||
</p>
|
||||
|
||||
return (
|
||||
<section className="hero-section hero-1 fix bg-cover" style={{ backgroundImage: `url('${getCmsImageUrl(data.backgroundImage)}')` }}>
|
||||
<div className="left-shape">
|
||||
<img src="/assets/img/home-1/hero/sape-2.png" alt="img" />
|
||||
</div>
|
||||
<div className="hero-shape">
|
||||
<img src="/assets/img/home-1/hero/shape.png" alt="img" />
|
||||
</div>
|
||||
<div className="top-shape">
|
||||
<img src="/assets/img/home-1/hero/shape-3.png" alt="img" />
|
||||
</div>
|
||||
<div className="right-shape">
|
||||
<img src="/assets/img/home-1/hero/shape-4.png" alt="img" />
|
||||
</div>
|
||||
<div className="pagi-item">
|
||||
<div className="dot-number">
|
||||
<span className="dot-num">
|
||||
<span>03</span>
|
||||
</span>
|
||||
<span className="dot-num">
|
||||
<span>05</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container-fluid">
|
||||
<div className="row align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="swiper hero-slider">
|
||||
<div className="swiper-wrapper">
|
||||
{slides.map((slide, index) => (
|
||||
<div className="swiper-slide" key={index}>
|
||||
<div className="hero-content">
|
||||
<h6>{slide.subtitle}</h6>
|
||||
<h1>
|
||||
{slide.title}
|
||||
{slide.videoUrl && (
|
||||
<a href={slide.videoUrl} className="video-btn video-popup">
|
||||
<i className="fa-solid fa-play"></i>
|
||||
</a>
|
||||
)}
|
||||
</h1>
|
||||
<p>
|
||||
{slide.description}
|
||||
</p>
|
||||
<div className="hero-button">
|
||||
{slide.primaryButton?.href && (
|
||||
<Link href={slide.primaryButton.href} className="theme-btn">
|
||||
{slide.primaryButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
)}
|
||||
{slide.secondaryButton?.href && (
|
||||
<Link href={slide.secondaryButton.href} className="theme-btn style-2">
|
||||
{slide.secondaryButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<div className="swiper image-slider">
|
||||
<div className="swiper-wrapper">
|
||||
{slides.map((slide, index) => (
|
||||
<div className="swiper-slide" key={index}>
|
||||
<div className="hero-image">
|
||||
<img src={slide.heroImage || firstSlide.heroImage || "/assets/img/home-1/hero/man.png"} alt="img" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
<div className="hero-home__actions">
|
||||
<button className="hero-home__btn hero-home__btn--primary">
|
||||
Explore Research
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</button>
|
||||
<button className="hero-home__btn hero-home__btn--secondary">
|
||||
Partner With Us
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeroSection;
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import { getCmsImageUrl } from '@/utils/image';
|
||||
|
||||
interface PartnersProps {
|
||||
data: {
|
||||
visaConsultancy: {
|
||||
items: {
|
||||
name: string;
|
||||
icon: string;
|
||||
year: string;
|
||||
}[];
|
||||
};
|
||||
brands: {
|
||||
items: {
|
||||
logo: string;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const Partners = ({ data }: PartnersProps) => {
|
||||
return (
|
||||
<>
|
||||
{/* Awards Section */}
|
||||
<section className="visa-consultency-section section-padding fix">
|
||||
<div className="container">
|
||||
<div className="row g-4">
|
||||
{(data.visaConsultancy?.items || []).map((partner, index) => (
|
||||
<div key={index} className="col-xl-3 col-lg-4 col-md-6">
|
||||
<div className="visa-consultency-item">
|
||||
<div className="image d-flex justify-content-center">
|
||||
<img src={getCmsImageUrl(partner.icon)} alt={partner.name} />
|
||||
</div>
|
||||
<h3>{partner.name}</h3>
|
||||
<h6>{partner.year}</h6>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Brand Partners Section */}
|
||||
<div className="brand-section fix">
|
||||
<div className="container">
|
||||
<div className="brand-wrapper style-1">
|
||||
<div className="brand-item">
|
||||
<div className="swiper brand-slider">
|
||||
<div className="swiper-wrapper">
|
||||
{(data.brands?.items || []).map((brand, index) => (
|
||||
<div key={index} className="swiper-slide">
|
||||
<div className="brand-image d-flex justify-content-center">
|
||||
<img src={getCmsImageUrl(brand.logo)} alt="brand-logo" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Partners;
|
||||
67
app/components/home/QuickLinksGrid.tsx
Normal file
67
app/components/home/QuickLinksGrid.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import Link from "next/link";
|
||||
|
||||
const LINKS = [
|
||||
{
|
||||
icon: "fa-solid fa-microscope",
|
||||
title: "Research Hub",
|
||||
desc: "Discover our ongoing projects, facilities, and interdisciplinary centers.",
|
||||
cta: "View Hub",
|
||||
href: "/research",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-book-open",
|
||||
title: "Publications",
|
||||
desc: "Access our extensive repository of peer-reviewed papers and journals.",
|
||||
cta: "Browse",
|
||||
href: "/publications",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-handshake",
|
||||
title: "Partnerships",
|
||||
desc: "Collaborate with us through industry, academic, and global networks.",
|
||||
cta: "Connect",
|
||||
href: "/partnerships",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-newspaper",
|
||||
title: "News & Events",
|
||||
desc: "Stay updated with our latest breakthroughs, seminars, and campus life.",
|
||||
cta: "Read More",
|
||||
href: "/blog",
|
||||
},
|
||||
];
|
||||
|
||||
const QuickLinksGrid = () => {
|
||||
return (
|
||||
<section id="quick-links" className="quick-links">
|
||||
<div className="container">
|
||||
<div className="quick-links__header text-center">
|
||||
<h2 className="quick-links__title">Explore Our Ecosystem</h2>
|
||||
<p className="quick-links__subtitle">
|
||||
Navigate through our core pillars of academic excellence and global partnerships.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="quick-links__grid">
|
||||
{LINKS.map((item, i) => (
|
||||
<Link href={item.href} key={i} className="quick-links__card">
|
||||
<div className="quick-links__icon-wrap">
|
||||
<i className={item.icon}></i>
|
||||
</div>
|
||||
<h3 className="quick-links__card-title">{item.title}</h3>
|
||||
<p className="quick-links__card-desc">{item.desc}</p>
|
||||
<div className="quick-links__card-footer">
|
||||
<span className="quick-links__cta">{item.cta}</span>
|
||||
<span className="quick-links__arrow">
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuickLinksGrid;
|
||||
@@ -1,74 +0,0 @@
|
||||
interface TestimonialsProps {
|
||||
data: {
|
||||
heading: string;
|
||||
subheading: string;
|
||||
videoUrl: string;
|
||||
videoThumbnail: string;
|
||||
items: {
|
||||
name: string;
|
||||
role: string;
|
||||
country: string;
|
||||
rating: number;
|
||||
comment: string;
|
||||
avatar: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
const Testimonials = ({ data }: TestimonialsProps) => {
|
||||
return (
|
||||
<section className="testimonial-section section-padding pb-0 fix">
|
||||
<div className="container">
|
||||
<div className="section-title text-center">
|
||||
<span className="sub-title wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">
|
||||
{data.heading}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="testimonial-wrapper">
|
||||
<div className="row g-4">
|
||||
<div className="col-lg-4">
|
||||
<div className="testimonia-image tp-clip-anim p-relative">
|
||||
<img src={data.videoThumbnail} alt="img" className="tp-anim-img" data-animate="true" />
|
||||
<a href={data.videoUrl} className="video-btn video-popup">
|
||||
<i className="fa-solid fa-play"></i></a>
|
||||
<h5>Real stories</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-8">
|
||||
<div className="swiper testimonial-slider">
|
||||
<div className="swiper-wrapper">
|
||||
{data.items.map((testimonial, index) => (
|
||||
<div key={index} className="swiper-slide">
|
||||
<div className="testimonial-box">
|
||||
<div className="star">
|
||||
{Array.from({ length: testimonial.rating }).map((_, i) => (
|
||||
<i key={i} className="fa-solid fa-star"></i>
|
||||
))}
|
||||
</div>
|
||||
<p>
|
||||
{testimonial.comment}
|
||||
</p>
|
||||
<div className="info-item">
|
||||
<div className="client-image">
|
||||
<img src={testimonial.avatar} alt="img" />
|
||||
</div>
|
||||
<div className="content">
|
||||
<h5>{testimonial.name}</h5>
|
||||
<span>{testimonial.country}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Testimonials;
|
||||
@@ -1,35 +0,0 @@
|
||||
interface VideoGalleryProps {
|
||||
data: {
|
||||
heading: string;
|
||||
videoUrl: string;
|
||||
thumbnail: string;
|
||||
};
|
||||
}
|
||||
|
||||
const VideoGallery = ({ data }: VideoGalleryProps) => {
|
||||
return (
|
||||
<section className="video-section bg-cover">
|
||||
<video autoPlay loop muted playsInline className="video-bg">
|
||||
<source src={data.videoUrl} type="video/mp4" />
|
||||
</video>
|
||||
<div className="text-image">
|
||||
<img src="/assets/img/home-1/feature/text.png" alt="img" />
|
||||
</div>
|
||||
<div className="text-image-2">
|
||||
<img src="/assets/img/home-1/feature/text-2.png" alt="img" />
|
||||
</div>
|
||||
<div className="container">
|
||||
<div className="video-content">
|
||||
<div className="shape">
|
||||
<img src="/assets/img/home-1/feature/Vector.png" alt="img" />
|
||||
</div>
|
||||
<h2 className="split-text-right split-text-in-right">{data.heading.split(' ').map((word, index) => (
|
||||
<span key={index}>{word}{index === 0 ? <br /> : ' '}</span>
|
||||
))}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoGallery;
|
||||
@@ -1,82 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
interface VisaCountriesProps {
|
||||
data: {
|
||||
heading: string;
|
||||
subheading: string;
|
||||
description: string;
|
||||
countries: {
|
||||
name: string;
|
||||
code: string;
|
||||
flag: string;
|
||||
link: string;
|
||||
visaTypes: string[];
|
||||
}[];
|
||||
ctaButton: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const VisaCountries = ({ data }: VisaCountriesProps) => {
|
||||
// Display the first country as featured
|
||||
const featuredCountry = data.countries[0];
|
||||
const halfLength = Math.ceil(featuredCountry.visaTypes.length / 2);
|
||||
const firstColumn = featuredCountry.visaTypes.slice(0, halfLength);
|
||||
const secondColumn = featuredCountry.visaTypes.slice(halfLength);
|
||||
|
||||
return (
|
||||
<section className="feature-section section-padding fix bg-cover" style={{ backgroundImage: "url('/assets/img/home-1/feature/bg.png')" }}>
|
||||
<div className="container">
|
||||
<div className="feature-wrapper">
|
||||
<div className="row g-4">
|
||||
<div className="col-lg-6">
|
||||
<div className="feature-content">
|
||||
<div className="section-title mb-0">
|
||||
<span className="sub-title bg-2 wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="text-white split-text-right split-text-in-right">
|
||||
{data.heading}
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text wow fadeInUp" data-wow-delay=".3s">
|
||||
{data.description}
|
||||
</p>
|
||||
<div className="feature-list-item wow fadeInUp" data-wow-delay=".5s">
|
||||
<ul className="list">
|
||||
{firstColumn.map((visaType, index) => (
|
||||
<li key={index}>
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
{visaType}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<ul className="list">
|
||||
{secondColumn.map((visaType, index) => (
|
||||
<li key={index}>
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
{visaType}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<Link href={data.ctaButton.href} className="theme-btn">
|
||||
{data.ctaButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<div className="feature-image">
|
||||
<img src={featuredCountry.flag} alt="img" />
|
||||
<h6>{featuredCountry.code}.{featuredCountry.name}</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default VisaCountries;
|
||||
@@ -1,52 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
interface VisaSolutionsProps {
|
||||
data: {
|
||||
heading: string;
|
||||
subheading: string;
|
||||
items: {
|
||||
number: string;
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
const VisaSolutions = ({ data }: VisaSolutionsProps) => {
|
||||
return (
|
||||
<div className="service-section section-padding fix">
|
||||
<div className="container">
|
||||
<div className="section-title text-center">
|
||||
<span className="sub-title wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">
|
||||
{data.heading}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
{data.items.map((item, index) => (
|
||||
<div key={index} className={`service-wrapper ${index === 1 ? 'active' : ''}`}>
|
||||
<div className="container">
|
||||
<div className="service-item">
|
||||
|
||||
<div className="left-item">
|
||||
<h5 className="number">{item.number}</h5>
|
||||
<h3>
|
||||
<Link href={item.link}>{item.title}</Link>
|
||||
</h3>
|
||||
</div>
|
||||
<div className="right-item">
|
||||
<p>
|
||||
{item.description}
|
||||
</p>
|
||||
<Link href={item.link} className="service-btn">Service Details <i className="fa-solid fa-arrow-right"></i></Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VisaSolutions;
|
||||
@@ -1,109 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
interface WhyChooseUsProps {
|
||||
data: {
|
||||
heading: string;
|
||||
highlightWord?: string;
|
||||
subheading: string;
|
||||
description: string;
|
||||
mainImage?: string;
|
||||
secondaryImage?: string;
|
||||
items: {
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
}[];
|
||||
features: string[];
|
||||
ctaButton: {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const WhyChooseUs = ({ data }: WhyChooseUsProps) => {
|
||||
const highlight = data.highlightWord?.trim();
|
||||
|
||||
let headingContent: React.ReactNode = data.heading;
|
||||
|
||||
if (highlight) {
|
||||
const index = data.heading.indexOf(highlight);
|
||||
if (index !== -1) {
|
||||
const before = data.heading.slice(0, index);
|
||||
const after = data.heading.slice(index + highlight.length);
|
||||
headingContent = (
|
||||
<>
|
||||
{before}
|
||||
<span>{highlight}</span>
|
||||
{after}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="about-section section-padding fix pb-0">
|
||||
<div className="top-shape">
|
||||
<img src="/assets/img/home-1/about/globe.png" alt="img" />
|
||||
</div>
|
||||
<div className="container">
|
||||
<div className="about-wrapper">
|
||||
<div className="row g-4">
|
||||
<div className="col-lg-6">
|
||||
<div className="about-image">
|
||||
<img src={data.mainImage || "/assets/img/home-1/about/about-1.jpg"} alt="img" className="wow img-custom-anim-left" />
|
||||
<div className="about-image-2">
|
||||
<img src={data.secondaryImage || "/assets/img/home-1/about/about-02.jpg"} alt="img" className="wow img-custom-anim-right" />
|
||||
</div>
|
||||
<div className="bg-shape">
|
||||
<img src="/assets/img/home-1/about/Vector.png" alt="img" />
|
||||
</div>
|
||||
<div className="plane-shape float-bob-y">
|
||||
<img src="/assets/img/home-1/about/plane.png" alt="img" />
|
||||
</div>
|
||||
<div className="top-shape float-bob-y">
|
||||
<img src="/assets/img/home-1/about/shape.png" alt="img" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<div className="about-content">
|
||||
<div className="section-title mb-0">
|
||||
<span className="sub-title wow fadeInUp">{data.subheading}</span>
|
||||
<h2 className="split-text-right split-text-in-right">
|
||||
{headingContent}
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text wow fadeInUp" data-wow-delay=".3s">
|
||||
{data.description}
|
||||
</p>
|
||||
<div className="about-item wow fadeInUp" data-wow-delay=".5s">
|
||||
{data.items.map((item, index) => (
|
||||
<div key={index} className="content">
|
||||
<span><img src={item.icon} alt="" /> {item.title}-</span>
|
||||
<p>{item.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<ul className="list wow fadeInUp" data-wow-delay=".3s">
|
||||
{data.features.map((feature, index) => (
|
||||
<li key={index}>
|
||||
<i className="fa-solid fa-chevrons-right"></i>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link href={data.ctaButton.href} className="theme-btn wow fadeInUp" data-wow-delay=".5s">
|
||||
{data.ctaButton.label}
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default WhyChooseUs;
|
||||
514
app/components/home/home.css
Normal file
514
app/components/home/home.css
Normal file
@@ -0,0 +1,514 @@
|
||||
/* ============================================================
|
||||
HOME PAGE — shared styles
|
||||
============================================================ */
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Hero Section
|
||||
------------------------------------------------------------ */
|
||||
.hero-home {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 560px;
|
||||
background-color: #1b254b;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-home__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.hero-home__bg-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
mix-blend-mode: overlay;
|
||||
}
|
||||
|
||||
.hero-home__gradient {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to right, #1b254b, rgba(27, 37, 75, 0.9), transparent);
|
||||
}
|
||||
|
||||
.hero-home__container {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.hero-home__container {
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-home__content {
|
||||
max-width: 42rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
/* Badge */
|
||||
.hero-home__badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: 9999px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(4px);
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.hero-home__badge-dot {
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: 50%;
|
||||
background: #60a5fa;
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.hero-home__badge-text {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: #bfdbfe;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* Title */
|
||||
.hero-home__title {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.02em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.hero-home__title {
|
||||
font-size: 3.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Description */
|
||||
.hero-home__desc {
|
||||
font-size: 1.125rem;
|
||||
color: #bfdbfe;
|
||||
line-height: 1.7;
|
||||
max-width: 36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
.hero-home__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.hero-home__btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.hero-home__btn--primary {
|
||||
background: #ffffff;
|
||||
color: #1b254b;
|
||||
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.hero-home__btn--primary:hover {
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.hero-home__btn--secondary {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.hero-home__btn--secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Research Impact Section
|
||||
------------------------------------------------------------ */
|
||||
.research-impact {
|
||||
padding: 80px 0;
|
||||
background-color: #f8fbff;
|
||||
}
|
||||
|
||||
.research-impact__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.research-impact__title {
|
||||
font-size: 1.6rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.research-impact__year {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
color: #6b7280;
|
||||
background: #e5e7eb;
|
||||
padding: 4px 12px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.research-impact__stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1.25rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.research-impact__stats {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 575px) {
|
||||
.research-impact__stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.research-impact__stat-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.research-impact__stat-label {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: #6b7280;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.research-impact__stat-value-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.research-impact__stat-value {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.research-impact__stat-trend {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.research-impact__stat-trend--up {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
.research-impact__stat-trend--down {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.research-impact__stat-trend--stable {
|
||||
background: #e5e7eb;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.research-impact__stat-sub {
|
||||
font-size: 0.8rem;
|
||||
color: #9ca3af;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.research-impact__charts {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.research-impact__charts {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.research-impact__chart-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
padding: 1.75rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.research-impact__chart-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.research-impact__chart-sub {
|
||||
font-size: 0.8rem;
|
||||
color: #9ca3af;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.research-impact__bar-chart {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 1.5rem;
|
||||
height: 160px;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.research-impact__bar-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.research-impact__bar {
|
||||
width: 100%;
|
||||
border-radius: 6px 6px 0 0;
|
||||
min-height: 8px;
|
||||
transition: height 0.4s ease;
|
||||
}
|
||||
|
||||
.research-impact__bar--journals {
|
||||
background: #1b254b;
|
||||
}
|
||||
|
||||
.research-impact__bar--conferences {
|
||||
background: #74c0fc;
|
||||
}
|
||||
|
||||
.research-impact__bar-label {
|
||||
font-size: 0.78rem;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.research-impact__donut-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.research-impact__donut {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
-webkit-mask: radial-gradient(circle, transparent 40%, black 41%);
|
||||
mask: radial-gradient(circle, transparent 40%, black 41%);
|
||||
}
|
||||
|
||||
.research-impact__legend {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.research-impact__legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.research-impact__legend-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.research-impact__legend-label {
|
||||
color: #374151;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.research-impact__legend-value {
|
||||
font-weight: 600;
|
||||
color: #1b254b;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------
|
||||
Quick Links Grid
|
||||
------------------------------------------------------------ */
|
||||
.quick-links {
|
||||
padding: 80px 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.quick-links__header {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.quick-links__title {
|
||||
font-size: clamp(1.75rem, 3vw, 2.25rem);
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.quick-links__subtitle {
|
||||
color: #6b7280;
|
||||
max-width: 40rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.quick-links__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.quick-links__grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 575px) {
|
||||
.quick-links__grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.quick-links__card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f8fbff;
|
||||
padding: 2rem;
|
||||
border-radius: 1.5rem;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
transition: box-shadow 0.2s ease, border-color 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.quick-links__card:hover {
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.08);
|
||||
border-color: #e5e7eb;
|
||||
}
|
||||
|
||||
.quick-links__icon-wrap {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
background: #ffffff;
|
||||
border-radius: 0.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.25rem;
|
||||
color: #1b254b;
|
||||
margin-bottom: 1.5rem;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.quick-links__card:hover .quick-links__icon-wrap {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.quick-links__card-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
color: #1b254b;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.quick-links__card-desc {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
flex: 1;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.quick-links__card-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quick-links__cta {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: #1b254b;
|
||||
}
|
||||
|
||||
.quick-links__arrow {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
background: #1b254b;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.quick-links__card:hover .quick-links__arrow {
|
||||
opacity: 1;
|
||||
}
|
||||
45
app/components/publications/PublicationHeader.tsx
Normal file
45
app/components/publications/PublicationHeader.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
|
||||
const PublicationHeader = () => {
|
||||
return (
|
||||
<section id="repo-header">
|
||||
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||
|
||||
{/* Title row + action buttons */}
|
||||
<div className="flex flex-col lg:flex-row justify-between items-start lg:items-end gap-6 mb-8 w-full">
|
||||
<div className="flex-1 max-w-3xl">
|
||||
<h1>Publication Repository</h1>
|
||||
<p>Search, filter, and access over 15,000 academic publications and research papers.</p>
|
||||
</div>
|
||||
<div className="flex gap-3 shrink-0">
|
||||
<button className="pub-btn-outline">
|
||||
<i className="fa-regular fa-bookmark"></i>
|
||||
Saved Searches
|
||||
</button>
|
||||
<button className="pub-btn-primary">
|
||||
<i className="fa-solid fa-download"></i>
|
||||
Export Results
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search bar */}
|
||||
<div className="pub-search-bar">
|
||||
<span className="pub-search-icon">
|
||||
<i className="fa-solid fa-magnifying-glass"></i>
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search by title, author, keyword, or DOI..."
|
||||
/>
|
||||
<div className="pub-search-btn-wrap">
|
||||
<button className="pub-btn-primary">Search</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublicationHeader;
|
||||
169
app/components/publications/PublicationResults.tsx
Normal file
169
app/components/publications/PublicationResults.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
'use client';
|
||||
import React, { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
|
||||
const SORT_OPTIONS = ['Relevance', 'Newest First', 'Oldest First', 'Most Cited'];
|
||||
|
||||
const PublicationResults = () => {
|
||||
const [isSortOpen, setIsSortOpen] = useState(false);
|
||||
const [selectedSort, setSelectedSort] = useState('Relevance');
|
||||
|
||||
return (
|
||||
<div className="pub-results">
|
||||
|
||||
{/* Toolbar */}
|
||||
<div className="pub-results-toolbar">
|
||||
<p className="pub-results-count">
|
||||
Showing <strong>1-10</strong> of <strong>12,450</strong> results
|
||||
</p>
|
||||
|
||||
<div className="pub-sort-wrap">
|
||||
<label>Sort by:</label>
|
||||
<div className="pub-sort-dropdown">
|
||||
<button
|
||||
className={`pub-sort-dropdown-btn ${isSortOpen ? 'open' : ''}`}
|
||||
onClick={() => setIsSortOpen(!isSortOpen)}
|
||||
>
|
||||
<span>{selectedSort}</span>
|
||||
<i className="fa-solid fa-chevron-down"></i>
|
||||
</button>
|
||||
{isSortOpen && (
|
||||
<div className="pub-sort-dropdown-menu">
|
||||
{SORT_OPTIONS.map((opt) => (
|
||||
<div
|
||||
key={opt}
|
||||
className={`pub-sort-dropdown-option ${selectedSort === opt ? 'selected' : ''}`}
|
||||
onClick={() => { setSelectedSort(opt); setIsSortOpen(false); }}
|
||||
>
|
||||
{opt}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
<div className="pub-card-list">
|
||||
|
||||
{/* Card 1 */}
|
||||
<div className="pub-card">
|
||||
<div className="pub-card-top">
|
||||
<h3 className="pub-card-title">
|
||||
<Link href="#">The Evolution of Democratic Institutions in Post-War Europe</Link>
|
||||
</h3>
|
||||
<div className="pub-badges">
|
||||
<span className="pub-badge pub-badge-open">
|
||||
<i className="fa-solid fa-lock-open"></i> Open Access
|
||||
</span>
|
||||
<span className="pub-badge pub-badge-peer">Peer Reviewed</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pub-card-meta">
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-solid fa-user"></i>
|
||||
<strong>Dr. Elena Rostova</strong>, Prof. Marcus Chen
|
||||
</div>
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-regular fa-calendar"></i> October 2024
|
||||
</div>
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-solid fa-link"></i> DOI: 10.1038/s41586-024
|
||||
</div>
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-solid fa-building-columns"></i> Center for Political Studies
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="pub-card-abstract">
|
||||
This paper examines the structural shifts in Western European democratic frameworks from 1945 to 1980. By analyzing institutional archives across France, Germany, and Italy, the research identifies a distinct divergence in how parliamentary powers were consolidated versus distributed. The findings challenge traditional narratives of a uniform democratic resurgence, suggesting instead that local historical contexts heavily dictated the adoption of specific liberal norms.
|
||||
</p>
|
||||
|
||||
<div className="pub-keywords">
|
||||
<span className="pub-keywords-label">Keywords:</span>
|
||||
<span className="pub-keyword-tag">Democracy</span>
|
||||
<span className="pub-keyword-tag">European History</span>
|
||||
<span className="pub-keyword-tag">Institutions</span>
|
||||
</div>
|
||||
|
||||
<div className="pub-card-actions">
|
||||
<button className="pub-action-btn pub-action-btn-primary">
|
||||
<i className="fa-solid fa-file-pdf"></i> View PDF
|
||||
</button>
|
||||
<button className="pub-action-btn pub-action-btn-secondary">
|
||||
<i className="fa-solid fa-quote-right"></i> Cite
|
||||
</button>
|
||||
<button className="pub-action-btn pub-action-btn-secondary">
|
||||
<i className="fa-regular fa-bookmark"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Card 2 */}
|
||||
<div className="pub-card">
|
||||
<div className="pub-card-top">
|
||||
<h3 className="pub-card-title">
|
||||
<Link href="#">Cognitive Linguistics and the Framing of Modern Ethics</Link>
|
||||
</h3>
|
||||
<div className="pub-badges">
|
||||
<span className="pub-badge pub-badge-institutional">
|
||||
<i className="fa-solid fa-building-user"></i> Institutional
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pub-card-meta">
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-solid fa-user"></i>
|
||||
<strong>Dr. Sarah Jenkins</strong>
|
||||
</div>
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-regular fa-calendar"></i> August 2024
|
||||
</div>
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-solid fa-link"></i> DOI: 10.1016/j.cogling.2024
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="pub-card-abstract">
|
||||
An exploration into how metaphor and cognitive framing shape contemporary ethical debates. The study utilizes computational linguistics to analyze over 10,000 policy documents and public speeches, demonstrating a significant correlation between specific metaphorical structures and the resulting ethical policy frameworks adopted by legislative bodies.
|
||||
</p>
|
||||
|
||||
<div className="pub-card-actions">
|
||||
<button className="pub-action-btn pub-action-btn-primary">
|
||||
<i className="fa-solid fa-arrow-right-to-bracket"></i> Login to Access
|
||||
</button>
|
||||
<button className="pub-action-btn pub-action-btn-secondary">
|
||||
<i className="fa-solid fa-quote-right"></i> Cite
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Pagination */}
|
||||
<div className="pub-pagination">
|
||||
<button className="pub-page-btn" disabled>
|
||||
<i className="fa-solid fa-arrow-left"></i> Previous
|
||||
</button>
|
||||
|
||||
<div className="pub-page-numbers">
|
||||
<button className="pub-page-num active">1</button>
|
||||
<button className="pub-page-num">2</button>
|
||||
<button className="pub-page-num">3</button>
|
||||
<span className="pub-page-ellipsis">...</span>
|
||||
<button className="pub-page-num">124</button>
|
||||
</div>
|
||||
|
||||
<button className="pub-page-btn">
|
||||
Next <i className="fa-solid fa-arrow-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublicationResults;
|
||||
123
app/components/publications/PublicationSidebar.tsx
Normal file
123
app/components/publications/PublicationSidebar.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const YEARS = ['2024 (1,245)', '2023 (3,412)', '2022 (2,890)'];
|
||||
const DOMAINS = ['Liberal Arts (4,521)', 'Social Sciences (3,210)', 'Humanities (2,980)', 'Political Science (1,840)'];
|
||||
const ACCESS_TYPES = ['Open Access', 'Institutional Login', 'Request Access'];
|
||||
|
||||
const AccordionSection = ({
|
||||
title,
|
||||
open,
|
||||
onToggle,
|
||||
children,
|
||||
}: {
|
||||
title: string;
|
||||
open: boolean;
|
||||
onToggle: () => void;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<div className="pub-accordion-item">
|
||||
<button
|
||||
className={`pub-accordion-trigger ${open ? 'open' : ''}`}
|
||||
onClick={onToggle}
|
||||
>
|
||||
{title}
|
||||
<i className="fa-solid fa-chevron-down"></i>
|
||||
</button>
|
||||
<div className={`pub-accordion-body ${open ? 'open' : ''}`}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const PublicationSidebar = () => {
|
||||
const [isYearOpen, setIsYearOpen] = useState(true);
|
||||
const [isDomainOpen, setIsDomainOpen] = useState(true);
|
||||
const [isAccessOpen, setIsAccessOpen] = useState(true);
|
||||
const [minYear, setMinYear] = useState('');
|
||||
const [maxYear, setMaxYear] = useState('');
|
||||
|
||||
return (
|
||||
<aside className="pub-sidebar">
|
||||
<div className="pub-sidebar-inner">
|
||||
|
||||
<div className="pub-sidebar-header">
|
||||
<h2>
|
||||
<i className="fa-solid fa-filter"></i> Filters
|
||||
</h2>
|
||||
<button
|
||||
className="pub-clear-btn"
|
||||
onClick={() => { setMinYear(''); setMaxYear(''); }}
|
||||
>
|
||||
Clear All
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="pub-accordion">
|
||||
|
||||
{/* Publication Year */}
|
||||
<AccordionSection title="Publication Year" open={isYearOpen} onToggle={() => setIsYearOpen(!isYearOpen)}>
|
||||
<div className="pub-filter-list">
|
||||
{YEARS.map((year, idx) => (
|
||||
<label key={year} className="pub-filter-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="pub-checkbox"
|
||||
defaultChecked={idx === 0}
|
||||
/>
|
||||
<span>{year}</span>
|
||||
</label>
|
||||
))}
|
||||
<div className="pub-year-range">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="Min"
|
||||
value={minYear}
|
||||
onChange={(e) => setMinYear(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="Max"
|
||||
value={maxYear}
|
||||
onChange={(e) => setMaxYear(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AccordionSection>
|
||||
|
||||
{/* Research Domain */}
|
||||
<AccordionSection title="Research Domain" open={isDomainOpen} onToggle={() => setIsDomainOpen(!isDomainOpen)}>
|
||||
<div className="pub-filter-list">
|
||||
{DOMAINS.map((domain, idx) => (
|
||||
<label key={domain} className="pub-filter-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="pub-checkbox"
|
||||
defaultChecked={idx === 0}
|
||||
/>
|
||||
<span>{domain}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</AccordionSection>
|
||||
|
||||
{/* Access Type */}
|
||||
<AccordionSection title="Access Type" open={isAccessOpen} onToggle={() => setIsAccessOpen(!isAccessOpen)}>
|
||||
<div className="pub-filter-list">
|
||||
{ACCESS_TYPES.map((type) => (
|
||||
<label key={type} className="pub-filter-label">
|
||||
<input type="checkbox" className="pub-checkbox" />
|
||||
<span>{type}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</AccordionSection>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublicationSidebar;
|
||||
787
app/components/publications/publications.css
Normal file
787
app/components/publications/publications.css
Normal file
@@ -0,0 +1,787 @@
|
||||
/* ============================================================
|
||||
publications.css — Scoped under .pub-wrapper
|
||||
Matches the HTML reference design exactly.
|
||||
All rules are scoped to avoid conflicts with Bootstrap/main.css
|
||||
============================================================ */
|
||||
|
||||
/* --- Local CSS Variables (override globals for this page) --- */
|
||||
.pub-wrapper {
|
||||
--pub-blue: #263c6f;
|
||||
--pub-blue-hover: #1d2e55;
|
||||
--pub-blue-light: #f0f4f8;
|
||||
--pub-border: #e5e7eb;
|
||||
--pub-text: #111827;
|
||||
--pub-muted: #6b7280;
|
||||
--pub-bg: #f9fafb;
|
||||
--pub-accent: #3b82f6;
|
||||
|
||||
background-color: var(--pub-bg);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SEARCH HEADER SECTION
|
||||
============================================================ */
|
||||
.pub-wrapper #repo-header {
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid var(--pub-border);
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.pub-wrapper #repo-header h1 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--pub-text);
|
||||
letter-spacing: -0.025em;
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
.pub-wrapper #repo-header p {
|
||||
color: var(--pub-muted);
|
||||
font-size: 1.125rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Search bar */
|
||||
.pub-wrapper .pub-search-bar {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-search-bar input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 1rem 8rem 1rem 3rem;
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.75rem;
|
||||
font-size: 1.125rem;
|
||||
color: var(--pub-text);
|
||||
background-color: #ffffff;
|
||||
outline: none;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-search-bar input::placeholder {
|
||||
color: var(--pub-muted);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-search-bar input:focus {
|
||||
border-color: var(--pub-blue);
|
||||
box-shadow: 0 0 0 2px rgba(38, 60, 111, 0.15);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-search-bar .pub-search-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 1rem;
|
||||
transform: translateY(-50%);
|
||||
color: var(--pub-muted);
|
||||
font-size: 1.125rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-search-bar .pub-search-btn-wrap {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0.5rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
BUTTONS
|
||||
============================================================ */
|
||||
.pub-wrapper .pub-btn-primary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: var(--pub-blue);
|
||||
color: #ffffff;
|
||||
border: 1px solid var(--pub-blue);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-btn-primary:hover {
|
||||
background-color: var(--pub-blue-hover);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-btn-outline {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: #ffffff;
|
||||
color: var(--pub-text);
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, color 0.2s;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-btn-outline:hover {
|
||||
border-color: var(--pub-blue);
|
||||
color: var(--pub-blue);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
MAIN CONTENT LAYOUT
|
||||
============================================================ */
|
||||
.pub-wrapper #repo-content {
|
||||
padding-top: 2.5rem;
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.pub-wrapper .pub-layout {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SIDEBAR
|
||||
============================================================ */
|
||||
.pub-wrapper .pub-sidebar {
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.pub-wrapper .pub-sidebar {
|
||||
width: 20rem; /* 320px */
|
||||
min-width: 20rem;
|
||||
max-width: 20rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sidebar-inner {
|
||||
background-color: #ffffff;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--pub-border);
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
padding: 1.25rem;
|
||||
position: sticky;
|
||||
top: 7rem; /* below fixed header */
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sidebar-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid var(--pub-border);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sidebar-header h2 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
color: var(--pub-text);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sidebar-header h2 i {
|
||||
color: var(--pub-blue);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sidebar-header .pub-clear-btn {
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-accent);
|
||||
font-weight: 500;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sidebar-header .pub-clear-btn:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Accordion */
|
||||
.pub-wrapper .pub-accordion {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-accordion-item {
|
||||
/* no extra styles needed */
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-accordion-trigger {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
text-align: left;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
color: var(--pub-text);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-accordion-trigger i {
|
||||
font-size: 0.75rem;
|
||||
color: var(--pub-muted);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-accordion-trigger.open i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-accordion-body {
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-out, opacity 0.3s ease-out;
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-accordion-body.open {
|
||||
max-height: 600px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-accordion-body .pub-filter-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Filter checkbox labels */
|
||||
.pub-wrapper .pub-filter-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-filter-label span {
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-text);
|
||||
transition: color 0.15s;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-filter-label:hover span {
|
||||
color: var(--pub-blue);
|
||||
}
|
||||
|
||||
/* Custom checkbox */
|
||||
.pub-wrapper .pub-checkbox {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
width: 1.15em;
|
||||
height: 1.15em;
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.25em;
|
||||
background-color: #ffffff;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: background-color 0.15s, border-color 0.15s;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-checkbox::before {
|
||||
content: "";
|
||||
width: 0.65em;
|
||||
height: 0.65em;
|
||||
transform: scale(0);
|
||||
transition: transform 120ms ease-in-out;
|
||||
background-color: #ffffff;
|
||||
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-checkbox:checked {
|
||||
background-color: var(--pub-blue);
|
||||
border-color: var(--pub-blue);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-checkbox:checked::before {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
/* Year range inputs */
|
||||
.pub-wrapper .pub-year-range {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-year-range input {
|
||||
width: 50%;
|
||||
padding: 0.375rem 0.5rem;
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-text);
|
||||
background-color: #ffffff;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-year-range input:focus {
|
||||
border-color: var(--pub-blue);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
RESULTS AREA
|
||||
============================================================ */
|
||||
.pub-wrapper .pub-results {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Results toolbar */
|
||||
.pub-wrapper .pub-results-toolbar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
padding: 1rem;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--pub-border);
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.pub-wrapper .pub-results-toolbar {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-results-count {
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-text);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-results-count strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-wrap label {
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-select {
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-text);
|
||||
background-color: #ffffff;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-select:focus,
|
||||
.pub-wrapper .pub-sort-select:hover {
|
||||
border-color: var(--pub-blue);
|
||||
}
|
||||
|
||||
/* Sort dropdown (custom React dropdown) */
|
||||
.pub-wrapper .pub-sort-dropdown {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
background-color: #ffffff;
|
||||
color: var(--pub-text);
|
||||
cursor: pointer;
|
||||
min-width: 140px;
|
||||
transition: border-color 0.2s;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-btn:hover,
|
||||
.pub-wrapper .pub-sort-dropdown-btn.open {
|
||||
border-color: var(--pub-blue);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-btn i {
|
||||
font-size: 0.625rem;
|
||||
color: var(--pub-muted);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-btn.open i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-menu {
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
right: 0;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -2px rgba(0,0,0,0.04);
|
||||
z-index: 50;
|
||||
overflow: hidden;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-option {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s;
|
||||
color: var(--pub-text);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-option:hover {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-sort-dropdown-option.selected {
|
||||
background-color: var(--pub-blue-light);
|
||||
color: var(--pub-blue);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
PUBLICATION CARD
|
||||
============================================================ */
|
||||
.pub-wrapper .pub-card-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card {
|
||||
background-color: #ffffff;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--pub-border);
|
||||
padding: 1.5rem;
|
||||
transition: box-shadow 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card:hover {
|
||||
border-color: var(--pub-blue);
|
||||
box-shadow: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -2px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* Card top row: title + badges */
|
||||
.pub-wrapper .pub-card-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.pub-wrapper .pub-card-top {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--pub-text);
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card:hover .pub-card-title {
|
||||
color: var(--pub-blue);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card-title a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card-title a:hover {
|
||||
color: var(--pub-blue);
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
.pub-wrapper .pub-badges {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.25rem 0.625rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-badge-open {
|
||||
background-color: #f0fdf4;
|
||||
color: #15803d;
|
||||
border-color: #bbf7d0;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-badge-peer {
|
||||
background-color: var(--pub-blue-light);
|
||||
color: var(--pub-blue);
|
||||
border-color: rgba(38, 60, 111, 0.2);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-badge-institutional {
|
||||
background-color: #fefce8;
|
||||
color: #a16207;
|
||||
border-color: #fde68a;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-badge-request {
|
||||
background-color: #eff6ff;
|
||||
color: #1d4ed8;
|
||||
border-color: #bfdbfe;
|
||||
}
|
||||
|
||||
/* Card meta row */
|
||||
.pub-wrapper .pub-card-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.5rem 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-muted);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card-meta .pub-meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-card-meta .pub-meta-item strong {
|
||||
color: var(--pub-text);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Card abstract */
|
||||
.pub-wrapper .pub-card-abstract {
|
||||
font-size: 0.875rem;
|
||||
color: var(--pub-muted);
|
||||
line-height: 1.625;
|
||||
margin-bottom: 1rem;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Keywords */
|
||||
.pub-wrapper .pub-keywords {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-keywords-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
color: var(--pub-muted);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-keyword-tag {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background-color: #f3f4f6;
|
||||
color: #4b5563;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
/* Card actions */
|
||||
.pub-wrapper .pub-card-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--pub-border);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-action-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
transition: color 0.2s;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-action-btn-primary {
|
||||
color: var(--pub-blue);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-action-btn-primary:hover {
|
||||
color: var(--pub-blue-hover);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-action-btn-secondary {
|
||||
color: var(--pub-muted);
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-action-btn-secondary:hover {
|
||||
color: var(--pub-text);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
PAGINATION
|
||||
============================================================ */
|
||||
.pub-wrapper .pub-pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-top: 1px solid var(--pub-border);
|
||||
padding-top: 1.5rem;
|
||||
margin-top: 2rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid var(--pub-border);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
background-color: #ffffff;
|
||||
color: var(--pub-text);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, color 0.2s;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-btn:hover:not(:disabled) {
|
||||
border-color: var(--pub-blue);
|
||||
color: var(--pub-blue);
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-numbers {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.pub-wrapper .pub-page-numbers {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-num {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
background-color: #ffffff;
|
||||
color: var(--pub-text);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-num:hover {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-num.active {
|
||||
background-color: var(--pub-blue);
|
||||
color: #ffffff;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.pub-wrapper .pub-page-ellipsis {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--pub-muted);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
208
app/components/research/ProjectsAndCenters.tsx
Normal file
208
app/components/research/ProjectsAndCenters.tsx
Normal file
@@ -0,0 +1,208 @@
|
||||
import React from 'react';
|
||||
|
||||
// Khối chứa 2 cột: Active Projects Feed và Funding Calls
|
||||
const ProjectsAndCenters = () => {
|
||||
return (
|
||||
<section id="projects-centers">
|
||||
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
|
||||
|
||||
{/* --- CỘT TRÁI (7/12): ACTIVE PROJECTS LIST --- */}
|
||||
<div className="lg:col-span-7">
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<h2 className="text-2xl font-bold text-ui-text">Active Projects Feed</h2>
|
||||
<a href="#" className="text-sm font-medium text-brand-accent hover:text-brand-blue transition-colors">
|
||||
View All Projects
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
|
||||
{/* Project Item 1 */}
|
||||
<div className="project-card">
|
||||
<div className="project-icon project-icon-blue">
|
||||
<i className="text-2xl text-brand-blue inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M160 32c0-17.7 14.3-32 32-32h32c17.7 0 32 14.3 32 32c17.7 0 32 14.3 32 32V288c0 17.7-14.3 32-32 32c0 17.7-14.3 32-32 32H192c-17.7 0-32-14.3-32-32c-17.7 0-32-14.3-32-32V64c0-17.7 14.3-32 32-32zM32 448H320c70.7 0 128-57.3 128-128s-57.3-128-128-128V128c106 0 192 86 192 192c0 49.2-18.5 94-48.9 128H480c17.7 0 32 14.3 32 32s-14.3 32-32 32H320 32c-17.7 0-32-14.3-32-32s14.3-32 32-32zm80-64H304c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<div className="flex flex-wrap items-center gap-2 mb-2">
|
||||
<span className="badge badge-active">Active</span>
|
||||
<span className="text-xs text-ui-muted font-medium inline-flex items-center gap-1">
|
||||
<i className="inline-flex">
|
||||
<svg className="w-3 h-3" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM232 120V256c0 8 4 15.5 10.7 20l96 64c11 7.4 25.9 4.4 33.3-6.7s4.4-25.9-6.7-33.3L280 243.2V120c0-13.3-10.7-24-24-24s-24 10.7-24 24z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
Updated 2d ago
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-lg font-bold text-ui-text mb-1">Urban Microclimate Modeling</h4>
|
||||
<p className="text-sm text-ui-muted line-clamp-2 mb-3">
|
||||
Developing high-resolution predictive models for heat island effects in European metropolitan areas using machine learning.
|
||||
</p>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex -space-x-2">
|
||||
<img className="w-8 h-8 rounded-full border-2 border-white object-cover" src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-4.jpg" alt="Researcher" title="Dr. Alan Turing" />
|
||||
<img className="w-8 h-8 rounded-full border-2 border-white object-cover" src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-5.jpg" alt="Researcher" title="Dr. Marie Curie" />
|
||||
<div className="w-8 h-8 rounded-full border-2 border-white bg-ui-bg flex items-center justify-center text-[10px] font-bold text-ui-muted">+3</div>
|
||||
</div>
|
||||
<div className="w-32">
|
||||
<div className="flex justify-between text-xs mb-1">
|
||||
<span className="text-ui-muted">Progress</span>
|
||||
<span className="font-medium">65%</span>
|
||||
</div>
|
||||
<div className="progress-bar-track">
|
||||
<div className="progress-bar-fill progress-fill-blue" style={{ width: '65%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Project Item 2 */}
|
||||
<div className="project-card">
|
||||
<div className="project-icon project-icon-purple">
|
||||
<i className="text-2xl text-purple-600 inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M318.6 9.4c-12.5-12.5-32.8-12.5-45.3 0l-120 120c-12.5-12.5-12.5 32.8 0 45.3l16 16c12.5 12.5 32.8 12.5 45.3 0l4-4L325.4 293.4l-4 4c-12.5 12.5-12.5 32.8 0 45.3l16 16c12.5 12.5 32.8 12.5 45.3 0l120-120c12.5-12.5 12.5-32.8 0-45.3l-16-16c-12.5-12.5-32.8-12.5-45.3 0l-4 4L330.6 74.6l4-4c12.5-12.5 12.5-32.8 0-45.3l-16-16zm-152 288c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l48 48c12.5 12.5 32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-1.4-1.4L272 285.3 226.7 240 168 298.7l-1.4-1.4z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<div className="flex flex-wrap items-center gap-2 mb-2">
|
||||
<span className="badge badge-collection">Data Collection</span>
|
||||
<span className="text-xs text-ui-muted font-medium inline-flex items-center gap-1">
|
||||
<i className="inline-flex">
|
||||
<svg className="w-3 h-3" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM232 120V256c0 8 4 15.5 10.7 20l96 64c11 7.4 25.9 4.4 33.3-6.7s4.4-25.9-6.7-33.3L280 243.2V120c0-13.3-10.7-24-24-24s-24 10.7-24 24z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
Updated 1w ago
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-lg font-bold text-ui-text mb-1">Digital Rights in the EU Framework</h4>
|
||||
<p className="text-sm text-ui-muted line-clamp-2 mb-3">
|
||||
A comparative analysis of member state implementation of digital privacy directives and their impact on civil liberties.
|
||||
</p>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex -space-x-2">
|
||||
<img className="w-8 h-8 rounded-full border-2 border-white object-cover" src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-6.jpg" alt="Researcher" />
|
||||
<img className="w-8 h-8 rounded-full border-2 border-white object-cover" src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-7.jpg" alt="Researcher" />
|
||||
</div>
|
||||
<div className="w-32">
|
||||
<div className="flex justify-between text-xs mb-1">
|
||||
<span className="text-ui-muted">Progress</span>
|
||||
<span className="font-medium">30%</span>
|
||||
</div>
|
||||
<div className="progress-bar-track">
|
||||
<div className="progress-bar-fill progress-fill-accent" style={{ width: '30%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Project Item 3 */}
|
||||
<div className="project-card">
|
||||
<div className="project-icon project-icon-orange">
|
||||
<i className="text-2xl text-orange-600 inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M512 80c0 18-14.3 34.6-38.4 48c-29.1 16.1-72.5 27.5-122.3 30.9c-3.7-1.8-7.4-3.5-11.3-5C300.6 137.4 248.2 128 192 128c-8.3 0-16.4 .2-24.5 .6l-1.1-.6C142.3 114.6 128 98 128 80c0-44.2 86-80 192-80S512 35.8 512 80zM160.7 161.1c10.2-.7 20.7-1.1 31.3-1.1c62.2 0 117.4 12.3 152.5 31.4C369.3 204.9 384 221.7 384 240c0 4-.7 7.9-2.1 11.7c-4.6 13.2-17 25.3-35 35.5c0 0 0 0 0 0c-.1 .1-.3 .1-.4 .2l0 0 0 0c-.3 .2-.6 .3-.9 .5c-35 19.4-90.8 32-153.6 32c-59.6 0-112.9-11.3-148.2-29.1c-1.9-.9-3.7-1.9-5.5-2.9C14.3 274.6 0 258 0 240c0-34.8 53.4-64.5 128-75.4c10.5-1.5 21.4-2.7 32.7-3.5zM416 240c0-21.9-10.6-39.9-24.1-53.4c28.3-4.4 54.2-11.4 76.2-20.5c16.3-6.8 31.5-15.2 43.9-25.5V176c0 19.3-16.5 37.1-43.8 50.9c-14.6 7.4-32.4 13.7-52.4 18.5c.1-1.8 .2-3.5 .2-5.3zm-32 96c0 18-14.3 34.6-38.4 48c-1.8 1-3.6 1.9-5.5 2.9C304.9 404.7 251.6 416 192 416c-62.8 0-118.6-12.6-153.6-32C14.3 370.6 0 354 0 336V300.6c12.5 10.3 27.6 18.7 43.9 25.5C83.4 342.6 135.8 352 192 352s108.6-9.4 148.1-25.9c7.8-3.2 15.3-6.9 22.4-10.9c6.1-3.4 11.8-7.2 17.2-11.2c1.5-1.1 2.9-2.3 4.3-3.4V304v5.7V336zm32 0V304 278.1c19-4.2 36.5-9.5 52.1-16c16.3-6.8 31.5-15.2 43.9-25.5V272c0 10.5-5 21-14.9 30.9c-16.3 16.3-45 29.7-81.3 38.4c.1-1.7 .2-3.5 .2-5.3zM192 448c56.2 0 108.6-9.4 148.1-25.9c16.3-6.8 31.5-15.2 43.9-25.5V432c0 44.2-86 80-192 80S0 476.2 0 432V396.6c12.5 10.3 27.6 18.7 43.9 25.5C83.4 438.6 135.8 448 192 448z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<div className="flex flex-wrap items-center gap-2 mb-2">
|
||||
<span className="badge badge-review">Review</span>
|
||||
<span className="text-xs text-ui-muted font-medium inline-flex items-center gap-1">
|
||||
<i className="inline-flex">
|
||||
<svg className="w-3 h-3" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM232 120V256c0 8 4 15.5 10.7 20l96 64c11 7.4 25.9 4.4 33.3-6.7s4.4-25.9-6.7-33.3L280 243.2V120c0-13.3-10.7-24-24-24s-24 10.7-24 24z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
Updated 3w ago
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-lg font-bold text-ui-text mb-1">Behavioral Impacts of Universal Basic Income</h4>
|
||||
<p className="text-sm text-ui-muted line-clamp-2 mb-3">
|
||||
Longitudinal study tracking spending habits and employment outcomes in selected pilot regions across France.
|
||||
</p>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex -space-x-2">
|
||||
<img className="w-8 h-8 rounded-full border-2 border-white object-cover" src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-8.jpg" alt="Researcher" />
|
||||
<img className="w-8 h-8 rounded-full border-2 border-white object-cover" src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-9.jpg" alt="Researcher" />
|
||||
<img className="w-8 h-8 rounded-full border-2 border-white object-cover" src="https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-1.jpg" alt="Researcher" />
|
||||
</div>
|
||||
<div className="w-32">
|
||||
<div className="flex justify-between text-xs mb-1">
|
||||
<span className="text-ui-muted">Progress</span>
|
||||
<span className="font-medium">90%</span>
|
||||
</div>
|
||||
<div className="progress-bar-track">
|
||||
<div className="progress-bar-fill progress-fill-blue" style={{ width: '90%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- CỘT PHẢI (5/12): FUNDING CALLS --- */}
|
||||
<div className="lg:col-span-5">
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<h2 className="text-2xl font-bold text-ui-text">Funding Calls</h2>
|
||||
</div>
|
||||
|
||||
<div className="funding-card">
|
||||
<div className="space-y-4 flex-grow">
|
||||
|
||||
{/* Item 1 */}
|
||||
<div className="funding-item">
|
||||
<span className="funding-label-urgent">Closing Soon</span>
|
||||
<h4>EU Horizon 2025: Sustainable Tech</h4>
|
||||
<div className="funding-meta">
|
||||
<span className="funding-due">
|
||||
<i className="fa-regular fa-calendar"></i> Due Nov 15
|
||||
</span>
|
||||
<a href="#" className="funding-link">
|
||||
Details <i className="fa-solid fa-arrow-right" style={{fontSize:'0.625rem'}}></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Item 2 */}
|
||||
<div className="funding-item">
|
||||
<span className="funding-label-internal">Internal Grant</span>
|
||||
<h4>Seed Funding for AI Ethics</h4>
|
||||
<div className="funding-meta">
|
||||
<span className="funding-due">
|
||||
<i className="fa-regular fa-calendar"></i> Due Dec 01
|
||||
</span>
|
||||
<a href="#" className="funding-link">
|
||||
Details <i className="fa-solid fa-arrow-right" style={{fontSize:'0.625rem'}}></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<button className="funding-view-all">
|
||||
View All Opportunities
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectsAndCenters;
|
||||
167
app/components/research/ResearchDomains.tsx
Normal file
167
app/components/research/ResearchDomains.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
import React from 'react';
|
||||
|
||||
// Khối chứa danh sách các lĩnh vực nghiên cứu.
|
||||
const ResearchDomains = () => {
|
||||
return (
|
||||
<section id="research-domains">
|
||||
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||
|
||||
{/* Tiêu đề Section */}
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl lg:text-4xl font-bold text-ui-text mb-4">Research Domains</h2>
|
||||
<p className="text-ui-muted max-w-2xl mx-auto">
|
||||
Discover our core areas of expertise, where interdisciplinary teams tackle complex global challenges.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Grid chứa các thẻ (Cards) */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
|
||||
{/* Domain Card 1 (Nổi bật - Màu xanh) */}
|
||||
<div className="folder-tab folder-tab-blue group">
|
||||
{/* Hiệu ứng Glow */}
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-white/10 rounded-full blur-2xl -translate-y-1/2 translate-x-1/2 group-hover:scale-150 transition-transform duration-500"></div>
|
||||
|
||||
<div className="domain-icon-blue">
|
||||
<i className="text-2xl text-white inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
|
||||
<path fill="currentColor" d="M384 32H512c17.7 0 32 14.3 32 32s-14.3 32-32 32H398.4c-5.2 25.8-22.9 47.1-46.4 57.3V448H512c17.7 0 32 14.3 32 32s-14.3 32-32 32H320 128c-17.7 0-32-14.3-32-32s14.3-32 32-32H288V153.3c-23.5-10.3-41.2-31.6-46.4-57.3H128c-17.7 0-32-14.3-32-32s14.3-32 32-32H256c14.6-19.4 37.8-32 64-32s49.4 12.6 64 32zm55.6 288H584.4L512 195.8 439.6 320zM512 416c-62.9 0-115.2-34-126-78.9c-2.6-11 1-22.3 6.7-32.1l95.2-163.2c5-8.6 14.2-13.8 24.1-13.8s19.1 5.3 24.1 13.8l95.2 163.2c5.7 9.8 9.3 21.1 6.7 32.1C627.2 382 574.9 416 512 416zM126.8 195.8L54.4 320H199.3L126.8 195.8zM.9 337.1c-2.6-11 1-22.3 6.7-32.1l95.2-163.2c5-8.6 14.2-13.8 24.1-13.8s19.1 5.3 24.1 13.8l95.2 163.2c5.7 9.8 9.3 21.1 6.7 32.1C242 382 189.7 416 126.8 416S11.7 382 .9 337.1z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold mb-4">Law & Policy</h3>
|
||||
<p className="text-white/80 text-sm leading-relaxed mb-8 flex-grow">
|
||||
Investigating the evolution of international law, human rights, and public policy in a rapidly changing geopolitical landscape.
|
||||
</p>
|
||||
|
||||
<div className="domain-card-footer">
|
||||
<span className="domain-badge-glass">42 Centers</span>
|
||||
<i className="text-white/70 group-hover:text-white group-hover:translate-x-1 transition-all inline-flex">
|
||||
<svg className="w-4 h-4" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Domain Card 2 */}
|
||||
<div className="folder-tab folder-tab-light group">
|
||||
<div className="domain-icon-light">
|
||||
<i className="text-2xl text-brand-blue inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M184 0c30.9 0 56 25.1 56 56V456c0 30.9-25.1 56-56 56c-28.9 0-52.7-21.9-55.7-50.1c-5.2 1.4-10.7 2.1-16.3 2.1c-35.3 0-64-28.7-64-64c0-7.4 1.3-14.6 3.6-21.2C21.4 367.4 0 338.2 0 304c0-31.9 18.7-59.5 45.8-72.3C37.1 220.8 32 207 32 192c0-30.7 21.6-56.3 50.4-62.6C80.8 123.9 80 118 80 112c0-29.9 20.6-55.1 48.3-62.1C131.3 21.9 155.1 0 184 0zM328 0c28.9 0 52.6 21.9 55.7 49.9c27.8 7 48.3 32.1 48.3 62.1c0 6-.8 11.9-2.4 17.4c28.8 6.2 50.4 31.9 50.4 62.6c0 15-5.1 28.8-13.8 39.7C493.3 244.5 512 272.1 512 304c0 34.2-21.4 63.4-51.6 74.8c2.3 6.6 3.6 13.8 3.6 21.2c0 35.3-28.7 64-64 64c-5.6 0-11.1-.7-16.3-2.1c-3 28.2-26.8 50.1-55.7 50.1c-30.9 0-56-25.1-56-56V56c0-30.9 25.1-56 56-56z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold mb-4">Cognitive Science</h3>
|
||||
<p className="text-ui-muted text-sm leading-relaxed mb-8 flex-grow">
|
||||
Bridging psychology, neuroscience, and artificial intelligence to understand human cognition and behavior.
|
||||
</p>
|
||||
|
||||
<div className="domain-card-footer">
|
||||
<span className="domain-badge-white">28 Centers</span>
|
||||
<i className="text-ui-muted group-hover:text-brand-blue group-hover:translate-x-1 transition-all inline-flex">
|
||||
<svg className="w-4 h-4" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Domain Card 3 */}
|
||||
<div className="folder-tab folder-tab-light group">
|
||||
<div className="domain-icon-light">
|
||||
<i className="text-2xl text-brand-blue inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M266.3 48.3L232.5 73.6c-5.4 4-8.5 10.4-8.5 17.1v9.1c0 6.8 5.5 12.3 12.3 12.3c2.4 0 4.8-.7 6.8-2.1l41.8-27.9c2-1.3 4.4-2.1 6.8-2.1h1c6.2 0 11.3 5.1 11.3 11.3c0 3-1.2 5.9-3.3 8l-19.9 19.9c-5.8 5.8-12.9 10.2-20.7 12.8l-26.5 8.8c-5.8 1.9-9.6 7.3-9.6 13.4c0 3.7-1.5 7.3-4.1 10l-17.9 17.9c-6.4 6.4-9.9 15-9.9 24v4.3c0 16.4 13.6 29.7 29.9 29.7c11 0 21.2-6.2 26.1-16l4-8.1c2.4-4.8 7.4-7.9 12.8-7.9c4.5 0 8.7 2.1 11.4 5.7l16.3 21.7c2.1 2.9 5.5 4.5 9.1 4.5c8.4 0 13.9-8.9 10.1-16.4l-1.1-2.3c-3.5-7 0-15.5 7.5-18l21.2-7.1c7.6-2.5 12.7-9.6 12.7-17.6c0-10.3 8.3-18.6 18.6-18.6H400c8.8 0 16 7.2 16 16s-7.2 16-16 16H379.3c-7.2 0-14.2 2.9-19.3 8l-4.7 4.7c-2.1 2.1-3.3 5-3.3 8c0 6.2 5.1 11.3 11.3 11.3h11.3c6 0 11.8 2.4 16 6.6l6.5 6.5c1.8 1.8 2.8 4.3 2.8 6.8s-1 5-2.8 6.8l-7.5 7.5C386 262 384 266.9 384 272s2 10 5.7 13.7L408 304c10.2 10.2 24.1 16 38.6 16H454c6.5-20.2 10-41.7 10-64c0-111.4-87.6-202.4-197.7-207.7zm172 307.9c-3.7-2.6-8.2-4.1-13-4.1c-6 0-11.8-2.4-16-6.6L396 332c-7.7-7.7-18-12-28.9-12c-9.7 0-19.2-3.5-26.6-9.8L314 287.4c-11.6-9.9-26.4-15.4-41.7-15.4H251.4c-12.6 0-25 3.7-35.5 10.7L188.5 301c-17.8 11.9-28.5 31.9-28.5 53.3v3.2c0 17 6.7 33.3 18.7 45.3l16 16c8.5 8.5 20 13.3 32 13.3H248c13.3 0 24 10.7 24 24c0 2.5 .4 5 1.1 7.3c71.3-5.8 132.5-47.6 165.2-107.2zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM187.3 100.7c-6.2-6.2-16.4-6.2-22.6 0l-32 32c-6.2 6.2-6.2 16.4 0 22.6s16.4 6.2 22.6 0l32-32c6.2-6.2 6.2-16.4 0-22.6z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold mb-4">Environmental Studies</h3>
|
||||
<p className="text-ui-muted text-sm leading-relaxed mb-8 flex-grow">
|
||||
Developing sustainable solutions for climate change, resource management, and ecological preservation.
|
||||
</p>
|
||||
|
||||
<div className="domain-card-footer">
|
||||
<span className="domain-badge-white">35 Centers</span>
|
||||
<i className="text-ui-muted group-hover:text-brand-blue group-hover:translate-x-1 transition-all inline-flex">
|
||||
<svg className="w-4 h-4" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Domain Card 4 */}
|
||||
<div className="folder-tab folder-tab-light group">
|
||||
<div className="domain-icon-light">
|
||||
<i className="text-2xl text-brand-blue inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M248 0h16c13.3 0 24 10.7 24 24V34.7C368.4 48.1 431.9 111.6 445.3 192H448c17.7 0 32 14.3 32 32s-14.3 32-32 32H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h2.7C80.1 111.6 143.6 48.1 224 34.7V24c0-13.3 10.7-24 24-24zM64 288h64V416h40V288h64V416h48V288h64V416h40V288h64V420.3c.6 .3 1.2 .7 1.7 1.1l48 32c11.7 7.8 17 22.4 12.9 35.9S494.1 512 480 512H32c-14.1 0-26.5-9.2-30.6-22.7s1.1-28.1 12.9-35.9l48-32c.6-.4 1.2-.7 1.8-1.1V288z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold mb-4">History & Humanities</h3>
|
||||
<p className="text-ui-muted text-sm leading-relaxed mb-8 flex-grow">
|
||||
Preserving cultural heritage and analyzing historical contexts to inform contemporary societal debates.
|
||||
</p>
|
||||
|
||||
<div className="domain-card-footer">
|
||||
<span className="domain-badge-white">50 Centers</span>
|
||||
<i className="text-ui-muted group-hover:text-brand-blue group-hover:translate-x-1 transition-all inline-flex">
|
||||
<svg className="w-4 h-4" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Domain Card 5 */}
|
||||
<div className="folder-tab folder-tab-light group">
|
||||
<div className="domain-icon-light">
|
||||
<i className="text-2xl text-brand-blue inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M64 64c0-17.7-14.3-32-32-32S0 46.3 0 64V400c0 44.2 35.8 80 80 80H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H80c-8.8 0-16-7.2-16-16V64zm406.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L320 210.7l-57.4-57.4c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5-12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L240 221.3l57.4 57.4c12.5 12.5 32.8 12.5 45.3 0l128-128z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold mb-4">Economics</h3>
|
||||
<p className="text-ui-muted text-sm leading-relaxed mb-8 flex-grow">
|
||||
Analyzing global markets, behavioral economics, and policy impacts on socioeconomic development.
|
||||
</p>
|
||||
|
||||
<div className="domain-card-footer">
|
||||
<span className="domain-badge-white">19 Centers</span>
|
||||
<i className="text-ui-muted group-hover:text-brand-blue group-hover:translate-x-1 transition-all inline-flex">
|
||||
<svg className="w-4 h-4" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Domain Card 6 - CTA */}
|
||||
<div className="domain-card-cta group">
|
||||
<div className="domain-icon-cta">
|
||||
<i className="text-2xl text-brand-blue inline-flex">
|
||||
<svg className="w-6 h-6" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H48c-17.7 0-32 14.3-32 32s14.3 32 32 32H192V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H400c17.7 0 32-14.3 32-32s-14.3-32-32-32H256V80z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<h3 className="text-xl font-bold mb-2">View All Domains</h3>
|
||||
<p className="text-ui-muted text-sm">Explore our complete directory of 15+ research areas.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResearchDomains;
|
||||
101
app/components/research/ResearchHero.tsx
Normal file
101
app/components/research/ResearchHero.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
const ResearchHero = () => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<section id="research-hero">
|
||||
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||
<div className="flex flex-col lg:flex-row gap-12 items-center">
|
||||
|
||||
{/* --- CỘT TRÁI --- */}
|
||||
<div className="w-full lg:w-1/2 hero-left">
|
||||
|
||||
{/* Label: gạch ngang + "Research Hub" */}
|
||||
<div className="hero-label">
|
||||
<span className="hero-label-line"></span>
|
||||
<span className="hero-label-text">Research Hub</span>
|
||||
</div>
|
||||
|
||||
{/* Heading */}
|
||||
<h1>
|
||||
Pioneering <br />
|
||||
<span>Discovery</span>
|
||||
</h1>
|
||||
|
||||
{/* Description */}
|
||||
<p className="hero-desc">
|
||||
Explore our cutting-edge research domains, active projects, and interdisciplinary centers driving innovation in liberal arts and sciences.
|
||||
</p>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="hero-buttons">
|
||||
<button className="r-btn-primary" onClick={() => router.push('/research/search')}>
|
||||
Browse Projects <i className="fa-solid fa-arrow-right text-sm"></i>
|
||||
</button>
|
||||
<button className="r-btn-outline">
|
||||
View Publications
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- CỘT PHẢI: Visual composition --- */}
|
||||
<div className="w-full lg:w-1/2 relative">
|
||||
<div className="relative w-full aspect-square max-w-[600px] mx-auto">
|
||||
|
||||
{/* Glow nền */}
|
||||
<div className="absolute inset-0 bg-brand-light rounded-full blur-3xl opacity-50"></div>
|
||||
|
||||
{/* Main image card */}
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[80%] h-[80%] bg-white rounded-[32px] border border-ui-border shadow-2xl overflow-hidden z-10">
|
||||
<img
|
||||
className="w-full h-full object-cover"
|
||||
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/11d578de27-837b09c2ea77020bcb48.png"
|
||||
alt="Research laboratory"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent"></div>
|
||||
<div className="absolute bottom-0 left-0 p-6 w-full text-white">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="px-3 py-1 text-white text-xs font-bold rounded-full" style={{ backgroundColor: 'var(--r-accent)' }}>
|
||||
Featured
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="text-xl font-bold mb-1" style={{ fontFamily: 'Inter, sans-serif' }}>Cognitive Sciences Lab</h3>
|
||||
<p className="text-sm opacity-90" style={{ fontFamily: 'Inter, sans-serif' }}>Exploring the intersection of AI and human psychology.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Floating stat card 1 — Publications */}
|
||||
<div className="r-stat-card" style={{ top: '10%', right: '5%' }}>
|
||||
<div className="w-12 h-12 rounded-full flex items-center justify-center" style={{ backgroundColor: 'var(--r-blue-light)', color: 'var(--r-blue)' }}>
|
||||
<i className="fa-solid fa-book-open text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-bold" style={{ color: 'var(--r-text)', fontFamily: 'Inter, sans-serif' }}>12k+</p>
|
||||
<p className="text-xs font-medium" style={{ color: 'var(--r-muted)', fontFamily: 'Inter, sans-serif' }}>Publications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Floating stat card 2 — Active Projects */}
|
||||
<div className="r-stat-card" style={{ bottom: '15%', left: '0%' }}>
|
||||
<div className="w-12 h-12 rounded-full flex items-center justify-center" style={{ backgroundColor: '#f0fdf4', color: '#16a34a' }}>
|
||||
<i className="fa-solid fa-flask text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-bold" style={{ color: 'var(--r-text)', fontFamily: 'Inter, sans-serif' }}>340</p>
|
||||
<p className="text-xs font-medium" style={{ color: 'var(--r-muted)', fontFamily: 'Inter, sans-serif' }}>Active Projects</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResearchHero;
|
||||
68
app/components/research/ResearchResources.tsx
Normal file
68
app/components/research/ResearchResources.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
|
||||
// Khối chứa 2 banner: Research Guidance và Publication Repository
|
||||
const ResearchResources = () => {
|
||||
return (
|
||||
<section id="research-quick-links">
|
||||
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
|
||||
{/* --- Banner 1: Guidance Link --- */}
|
||||
<a href="#" className="resource-card group">
|
||||
<div className="resource-card-glow"></div>
|
||||
<div className="relative z-10 flex items-start gap-6">
|
||||
<div className="resource-icon">
|
||||
<i className="text-3xl text-brand-blue inline-flex">
|
||||
<svg className="w-8 h-8" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm50.7-186.9L162.4 380.6c-19.4 7.5-38.5-11.6-31-31l55.5-144.3c3.3-8.5 9.9-15.1 18.4-18.4l144.3-55.5c19.4-7.5 38.5 11.6 31 31L325.1 306.7c-3.2 8.5-9.9 15.1-18.4 18.4zM288 256a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-ui-text mb-2 group-hover:text-brand-blue transition-colors">
|
||||
Research Guidance
|
||||
</h3>
|
||||
<p className="text-ui-muted leading-relaxed mb-4">
|
||||
Access comprehensive resources, ethical guidelines, grant application support, and methodological frameworks for your research journey.
|
||||
</p>
|
||||
<span className="resource-link">
|
||||
Access Portal
|
||||
<i className="fa-solid fa-arrow-right group-hover:translate-x-1 transition-transform"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{/* --- Banner 2: Repository Link --- */}
|
||||
<a href="#" className="resource-card group">
|
||||
<div className="resource-card-glow"></div>
|
||||
<div className="relative z-10 flex items-start gap-6">
|
||||
<div className="resource-icon">
|
||||
<i className="text-3xl text-brand-blue inline-flex">
|
||||
<svg className="w-8 h-8" aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M0 96C0 43 43 0 96 0h96V190.7c0 13.4 15.5 20.9 26 12.5L272 160l54 43.2c10.5 8.4 26 .9 26-12.5V0h32 32c17.7 0 32 14.3 32 32V352c0 17.7-14.3 32-32 32v64c17.7 0 32 14.3 32 32s-14.3 32-32 32H384 96c-53 0-96-43-96-96V96zM64 416c0 17.7 14.3 32 32 32H352V384H96c-17.7 0-32 14.3-32 32z"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-ui-text mb-2 group-hover:text-brand-blue transition-colors">
|
||||
Publication Repository
|
||||
</h3>
|
||||
<p className="text-ui-muted leading-relaxed mb-4">
|
||||
Browse, search, and request access to thousands of peer-reviewed papers, dissertations, and datasets produced by ULP scholars.
|
||||
</p>
|
||||
<span className="resource-link">
|
||||
Search Repository
|
||||
<i className="fa-solid fa-arrow-right group-hover:translate-x-1 transition-transform"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResearchResources;
|
||||
115
app/components/research/ResearchSearch.tsx
Normal file
115
app/components/research/ResearchSearch.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
const ResearchSearch = () => {
|
||||
const [query, setQuery] = useState('');
|
||||
const [activeFilter, setActiveFilter] = useState('Researchers');
|
||||
const filters = ['Researchers', 'Labs', 'Projects', 'Institutes'];
|
||||
const router = useRouter();
|
||||
|
||||
const handleSearch = () => {
|
||||
const params = new URLSearchParams({ q: query, type: activeFilter });
|
||||
router.push(`/research/search?${params.toString()}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-5xl mx-auto mb-10" style={{ padding: '0 1rem' }}>
|
||||
|
||||
{/* Search bar */}
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
|
||||
<i className="fa-solid fa-magnifying-glass" style={{ color: '#9ca3af' }}></i>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
|
||||
placeholder="Search across researchers, labs, projects, and disciplines..."
|
||||
style={{
|
||||
width: '100%',
|
||||
paddingLeft: '3rem',
|
||||
paddingRight: '8rem',
|
||||
paddingTop: '1rem',
|
||||
paddingBottom: '1rem',
|
||||
backgroundColor: '#ffffff',
|
||||
border: '1px solid #e5e7eb',
|
||||
borderRadius: '1rem',
|
||||
boxShadow: '0 1px 2px 0 rgba(0,0,0,0.05)',
|
||||
fontSize: '1rem',
|
||||
color: '#374151',
|
||||
outline: 'none',
|
||||
transition: 'border-color 0.2s, box-shadow 0.2s',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
e.target.style.borderColor = '#263c6f';
|
||||
e.target.style.boxShadow = '0 0 0 2px rgba(38,60,111,0.15)';
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
e.target.style.borderColor = '#e5e7eb';
|
||||
e.target.style.boxShadow = '0 1px 2px 0 rgba(0,0,0,0.05)';
|
||||
}}
|
||||
/>
|
||||
<div className="absolute flex items-center" style={{ top: '0.5rem', bottom: '0.5rem', right: '0.5rem' }}>
|
||||
<button
|
||||
onClick={handleSearch}
|
||||
style={{
|
||||
backgroundColor: '#263c6f',
|
||||
color: '#ffffff',
|
||||
padding: '0.5rem 1.5rem',
|
||||
borderRadius: '0.75rem',
|
||||
fontSize: '0.875rem',
|
||||
fontWeight: 500,
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
height: '100%',
|
||||
transition: 'opacity 0.2s',
|
||||
}}
|
||||
onMouseEnter={(e) => (e.currentTarget.style.opacity = '0.9')}
|
||||
onMouseLeave={(e) => (e.currentTarget.style.opacity = '1')}
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Filter pills */}
|
||||
<div className="flex gap-3 mt-4 px-2" style={{ flexWrap: 'wrap', alignItems: 'center' }}>
|
||||
<span style={{ fontSize: '0.75rem', fontWeight: 500, color: '#6b7280', textTransform: 'uppercase', letterSpacing: '0.05em', marginTop: '0.25rem' }}>
|
||||
Filters:
|
||||
</span>
|
||||
{filters.map((filter) => (
|
||||
<button
|
||||
key={filter}
|
||||
onClick={() => setActiveFilter(filter)}
|
||||
style={{
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 500,
|
||||
padding: '0.25rem 0.75rem',
|
||||
borderRadius: '9999px',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
transition: 'background-color 0.2s',
|
||||
backgroundColor: activeFilter === filter ? 'rgba(38,60,111,0.1)' : '#f3f4f6',
|
||||
color: activeFilter === filter ? '#263c6f' : '#4b5563',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (activeFilter !== filter) e.currentTarget.style.backgroundColor = '#e5e7eb';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (activeFilter !== filter) e.currentTarget.style.backgroundColor = '#f3f4f6';
|
||||
}}
|
||||
>
|
||||
{filter}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResearchSearch;
|
||||
718
app/components/research/research.css
Normal file
718
app/components/research/research.css
Normal file
@@ -0,0 +1,718 @@
|
||||
/* ============================================================
|
||||
research.css — Scoped under .research-wrapper
|
||||
Matches the HTML reference design exactly.
|
||||
All rules scoped to avoid conflicts with Bootstrap/main.css
|
||||
============================================================ */
|
||||
|
||||
/* --- Local CSS Variables --- */
|
||||
.research-wrapper {
|
||||
--r-blue: #263c6f;
|
||||
--r-blue-hover: #1d2e55;
|
||||
--r-blue-light: #f0f4f8;
|
||||
--r-accent: #3b82f6;
|
||||
--r-border: #e5e7eb;
|
||||
--r-text: #111827;
|
||||
--r-muted: #6b7280;
|
||||
--r-bg: #f9fafb;
|
||||
--r-white: #ffffff;
|
||||
--r-shadow-soft: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
|
||||
--r-shadow-hover: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -2px rgba(0,0,0,0.04);
|
||||
|
||||
width: 100%;
|
||||
background-color: var(--r-bg);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
HERO SECTION
|
||||
============================================================ */
|
||||
.research-wrapper #research-hero {
|
||||
width: 100%;
|
||||
background-color: var(--r-bg);
|
||||
border-bottom: 1px solid var(--r-border);
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 4rem;
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
/* Label row: gạch ngang + text "Research Hub" */
|
||||
.research-wrapper #research-hero .hero-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.research-wrapper #research-hero .hero-label-line {
|
||||
display: block;
|
||||
width: 2rem;
|
||||
height: 2.5px;
|
||||
background-color: var(--r-accent);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.research-wrapper #research-hero .hero-label-text {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--r-blue);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
/* Heading */
|
||||
.research-wrapper #research-hero h1 {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-text);
|
||||
letter-spacing: -0.025em;
|
||||
line-height: 1.1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.research-wrapper #research-hero h1 {
|
||||
font-size: 4.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.research-wrapper #research-hero h1 span {
|
||||
color: var(--r-blue);
|
||||
}
|
||||
|
||||
/* Paragraph */
|
||||
.research-wrapper #research-hero .hero-desc {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-size: 1.125rem;
|
||||
color: var(--r-muted);
|
||||
line-height: 1.625;
|
||||
max-width: 36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Left column spacing */
|
||||
.research-wrapper #research-hero .hero-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
/* Button row */
|
||||
.research-wrapper #research-hero .hero-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Hero buttons */
|
||||
.research-wrapper .r-btn-primary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem 2rem;
|
||||
background-color: var(--r-blue);
|
||||
color: var(--r-white);
|
||||
border: none;
|
||||
border-radius: 9999px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.research-wrapper .r-btn-primary:hover {
|
||||
background-color: var(--r-blue-hover);
|
||||
color: var(--r-white);
|
||||
}
|
||||
|
||||
.research-wrapper .r-btn-outline {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem 2rem;
|
||||
background-color: var(--r-white);
|
||||
color: var(--r-text);
|
||||
border: 1px solid var(--r-border);
|
||||
border-radius: 9999px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.research-wrapper .r-btn-outline:hover {
|
||||
background-color: #f9fafb;
|
||||
color: var(--r-text);
|
||||
}
|
||||
|
||||
/* Hero floating stat cards */
|
||||
.research-wrapper .r-stat-card {
|
||||
position: absolute;
|
||||
background-color: var(--r-white);
|
||||
border-radius: 1rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--r-border);
|
||||
box-shadow: var(--r-shadow-hover);
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.research-wrapper .r-stat-card p {
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
RESEARCH DOMAINS SECTION
|
||||
============================================================ */
|
||||
.research-wrapper #research-domains {
|
||||
padding-top: 5rem;
|
||||
padding-bottom: 5rem;
|
||||
background-color: var(--r-white);
|
||||
}
|
||||
|
||||
.research-wrapper #research-domains h2 {
|
||||
font-size: 1.875rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-text);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.research-wrapper #research-domains h2 {
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.research-wrapper #research-domains > div > div:first-child p {
|
||||
color: var(--r-muted);
|
||||
max-width: 42rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Domain card — folder tab shape */
|
||||
.research-wrapper .folder-tab {
|
||||
clip-path: polygon(0 0, calc(100% - 40px) 0, 100% 40px, 100% 100%, 0 100%);
|
||||
padding: 2rem;
|
||||
min-height: 320px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 1.5rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.research-wrapper .folder-tab:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--r-shadow-hover);
|
||||
}
|
||||
|
||||
/* Blue variant (first card) */
|
||||
.research-wrapper .folder-tab-blue {
|
||||
background-color: var(--r-blue);
|
||||
color: var(--r-white);
|
||||
}
|
||||
|
||||
.research-wrapper .folder-tab-blue h3 {
|
||||
color: var(--r-white);
|
||||
}
|
||||
|
||||
.research-wrapper .folder-tab-blue p {
|
||||
color: rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
/* Light variant */
|
||||
.research-wrapper .folder-tab-light {
|
||||
background-color: var(--r-blue-light);
|
||||
color: var(--r-text);
|
||||
border: 1px solid var(--r-border);
|
||||
}
|
||||
|
||||
/* CTA card (dashed border) */
|
||||
.research-wrapper .domain-card-cta {
|
||||
border-radius: 1.5rem;
|
||||
padding: 2rem;
|
||||
min-height: 320px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
border: 2px dashed var(--r-border);
|
||||
background-color: var(--r-bg);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.research-wrapper .domain-card-cta:hover {
|
||||
border-color: var(--r-blue);
|
||||
}
|
||||
|
||||
.research-wrapper .domain-card-cta h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-text);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.research-wrapper .domain-card-cta p {
|
||||
font-size: 0.875rem;
|
||||
color: var(--r-muted);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Domain card icon box */
|
||||
.research-wrapper .domain-icon-blue {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
border-radius: 1rem;
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
backdrop-filter: blur(4px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 2rem;
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.research-wrapper .domain-icon-light {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
border-radius: 1rem;
|
||||
background-color: var(--r-white);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 2rem;
|
||||
border: 1px solid var(--r-border);
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.research-wrapper .domain-card-cta .domain-icon-cta {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--r-white);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 1rem;
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.research-wrapper .domain-card-cta:hover .domain-icon-cta {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* Domain card footer row */
|
||||
.research-wrapper .domain-card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.research-wrapper .domain-badge-white {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
background-color: var(--r-white);
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid var(--r-border);
|
||||
color: var(--r-blue);
|
||||
}
|
||||
|
||||
.research-wrapper .domain-badge-glass {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 9999px;
|
||||
color: var(--r-white);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
PROJECTS & CENTERS SECTION
|
||||
============================================================ */
|
||||
.research-wrapper #projects-centers {
|
||||
padding-top: 5rem;
|
||||
padding-bottom: 5rem;
|
||||
background-color: var(--r-bg);
|
||||
border-top: 1px solid var(--r-border);
|
||||
border-bottom: 1px solid var(--r-border);
|
||||
}
|
||||
|
||||
.research-wrapper #projects-centers h2 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-text);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Project item card */
|
||||
.research-wrapper .project-card {
|
||||
background-color: var(--r-white);
|
||||
border-radius: 1.25rem;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--r-border);
|
||||
box-shadow: var(--r-shadow-soft);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
align-items: flex-start;
|
||||
transition: box-shadow 0.25s ease;
|
||||
}
|
||||
|
||||
.research-wrapper .project-card:hover {
|
||||
box-shadow: var(--r-shadow-hover);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.research-wrapper .project-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.research-wrapper .project-icon {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
border-radius: 0.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid var(--r-border);
|
||||
}
|
||||
|
||||
.research-wrapper .project-icon-blue { background-color: var(--r-blue-light); border-color: var(--r-border); }
|
||||
.research-wrapper .project-icon-purple { background-color: #faf5ff; border-color: #e9d5ff; }
|
||||
.research-wrapper .project-icon-orange { background-color: #fff7ed; border-color: #fed7aa; }
|
||||
|
||||
/* Status badges */
|
||||
.research-wrapper .badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.625rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.research-wrapper .badge-active { background-color: #f0fdf4; color: #15803d; border-color: #bbf7d0; }
|
||||
.research-wrapper .badge-collection { background-color: #fefce8; color: #a16207; border-color: #fde68a; }
|
||||
.research-wrapper .badge-review { background-color: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
|
||||
|
||||
/* Progress bar */
|
||||
.research-wrapper .progress-bar-track {
|
||||
width: 8rem;
|
||||
background-color: var(--r-bg);
|
||||
border-radius: 9999px;
|
||||
height: 0.375rem;
|
||||
}
|
||||
|
||||
.research-wrapper .progress-bar-fill {
|
||||
height: 0.375rem;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.research-wrapper .progress-fill-blue { background-color: var(--r-blue); }
|
||||
.research-wrapper .progress-fill-accent { background-color: var(--r-accent); }
|
||||
|
||||
/* ============================================================
|
||||
FUNDING CALLS (right column)
|
||||
============================================================ */
|
||||
.research-wrapper .funding-card {
|
||||
background-color: var(--r-white);
|
||||
border-radius: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--r-border);
|
||||
box-shadow: var(--r-shadow-soft);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: box-shadow 0.25s ease;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-card:hover {
|
||||
box-shadow: var(--r-shadow-hover);
|
||||
}
|
||||
|
||||
.research-wrapper .funding-item {
|
||||
padding: 1.25rem;
|
||||
background-color: var(--r-bg);
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--r-border);
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-item:hover {
|
||||
border-color: var(--r-accent);
|
||||
}
|
||||
|
||||
.research-wrapper .funding-item h4 {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-text);
|
||||
margin: 0 0 0.75rem 0;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-label-urgent {
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
color: #ef4444;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-label-internal {
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-blue);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-due {
|
||||
font-size: 0.75rem;
|
||||
color: var(--r-muted);
|
||||
font-weight: 500;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-link {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--r-blue);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
text-decoration: none;
|
||||
transition: color 0.15s;
|
||||
}
|
||||
|
||||
.research-wrapper .funding-link:hover {
|
||||
color: var(--r-blue-hover);
|
||||
}
|
||||
|
||||
.research-wrapper .funding-view-all {
|
||||
width: 100%;
|
||||
margin-top: 1.5rem;
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid var(--r-border);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--r-text);
|
||||
background-color: var(--r-white);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, color 0.2s;
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.research-wrapper .funding-view-all:hover {
|
||||
border-color: var(--r-blue);
|
||||
color: var(--r-blue);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
RESEARCH RESOURCES (Quick Links)
|
||||
============================================================ */
|
||||
.research-wrapper #research-quick-links {
|
||||
padding-top: 5rem;
|
||||
padding-bottom: 5rem;
|
||||
background-color: var(--r-white);
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card {
|
||||
display: block;
|
||||
background-color: var(--r-bg);
|
||||
border-radius: 1.5rem;
|
||||
padding: 2rem;
|
||||
border: 1px solid var(--r-border);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card:hover {
|
||||
border-color: var(--r-accent);
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card-glow {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 16rem;
|
||||
height: 16rem;
|
||||
background-color: var(--r-blue-light);
|
||||
border-radius: 9999px;
|
||||
filter: blur(64px);
|
||||
opacity: 0.5;
|
||||
transform: translateY(-50%) translateX(25%);
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card:hover .resource-card-glow {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.research-wrapper .resource-icon {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
border-radius: 1rem;
|
||||
background-color: var(--r-white);
|
||||
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
|
||||
border: 1px solid var(--r-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card:hover .resource-icon {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-text);
|
||||
margin-bottom: 0.5rem;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card:hover h3 {
|
||||
color: var(--r-blue);
|
||||
}
|
||||
|
||||
.research-wrapper .resource-card p {
|
||||
color: var(--r-muted);
|
||||
line-height: 1.625;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.research-wrapper .resource-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--r-blue);
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
COLLABORATION CTA SECTION
|
||||
============================================================ */
|
||||
.research-wrapper #collaboration-cta {
|
||||
padding-top: 6rem;
|
||||
padding-bottom: 6rem;
|
||||
background-color: var(--r-blue);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.research-wrapper #collaboration-cta h2 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--r-white);
|
||||
letter-spacing: -0.025em;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.research-wrapper #collaboration-cta h2 { font-size: 3rem; }
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.research-wrapper #collaboration-cta h2 { font-size: 3.75rem; }
|
||||
}
|
||||
|
||||
.research-wrapper #collaboration-cta p {
|
||||
font-size: 1.25rem;
|
||||
color: var(--r-blue-light);
|
||||
opacity: 0.9;
|
||||
line-height: 1.625;
|
||||
max-width: 42rem;
|
||||
margin: 0 auto 2.5rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.research-wrapper .cta-btn-white {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem 2rem;
|
||||
background-color: var(--r-white);
|
||||
color: var(--r-blue);
|
||||
border: none;
|
||||
border-radius: 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1);
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.research-wrapper .cta-btn-white { width: auto; }
|
||||
}
|
||||
|
||||
.research-wrapper .cta-btn-white:hover {
|
||||
background-color: #f9fafb;
|
||||
color: var(--r-blue);
|
||||
}
|
||||
|
||||
.research-wrapper .cta-btn-ghost {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem 2rem;
|
||||
background-color: transparent;
|
||||
color: var(--r-white);
|
||||
border: 2px solid rgba(255,255,255,0.3);
|
||||
border-radius: 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.research-wrapper .cta-btn-ghost { width: auto; }
|
||||
}
|
||||
|
||||
.research-wrapper .cta-btn-ghost:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: var(--r-white);
|
||||
}
|
||||
79
app/components/research/search/ResearchSearchHeader.tsx
Normal file
79
app/components/research/search/ResearchSearchHeader.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
const FILTERS = ['Researchers', 'Labs', 'Projects', 'Institutes'];
|
||||
|
||||
const ResearchSearchHeader = () => {
|
||||
const [query, setQuery] = useState('');
|
||||
const [activeFilter, setActiveFilter] = useState('Researchers');
|
||||
const router = useRouter();
|
||||
|
||||
const handleSearch = () => {
|
||||
const params = new URLSearchParams({ q: query, type: activeFilter });
|
||||
router.push(`/research/search?${params.toString()}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="repo-header">
|
||||
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||
|
||||
{/* Title row */}
|
||||
<div className="flex flex-col lg:flex-row justify-between items-start lg:items-end gap-6 mb-8 w-full">
|
||||
<div className="flex-1 max-w-3xl">
|
||||
<h1>Research Search</h1>
|
||||
<p>Search across researchers, labs, active projects, and institutes.</p>
|
||||
</div>
|
||||
<div className="flex gap-3 shrink-0">
|
||||
<button className="pub-btn-outline" onClick={() => router.back()}>
|
||||
<i className="fa-solid fa-arrow-left"></i>
|
||||
Back to Research
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search bar */}
|
||||
<div className="pub-search-bar">
|
||||
<span className="pub-search-icon">
|
||||
<i className="fa-solid fa-magnifying-glass"></i>
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search researchers, labs, projects, and disciplines..."
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
|
||||
/>
|
||||
<div className="pub-search-btn-wrap">
|
||||
<button className="pub-btn-primary" onClick={handleSearch}>Search</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Filter tabs */}
|
||||
<div className="flex flex-wrap items-center gap-3 mt-5">
|
||||
<span className="text-xs font-bold uppercase tracking-widest" style={{ color: 'var(--pub-muted)' }}>
|
||||
Filter by:
|
||||
</span>
|
||||
{FILTERS.map((f) => (
|
||||
<button
|
||||
key={f}
|
||||
onClick={() => setActiveFilter(f)}
|
||||
className="pub-btn-outline"
|
||||
style={activeFilter === f ? {
|
||||
backgroundColor: 'var(--pub-blue-light)',
|
||||
color: 'var(--pub-blue)',
|
||||
borderColor: 'transparent',
|
||||
} : {}}
|
||||
>
|
||||
{f}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResearchSearchHeader;
|
||||
177
app/components/research/search/ResearchSearchResults.tsx
Normal file
177
app/components/research/search/ResearchSearchResults.tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const SORT_OPTIONS = ['Relevance', 'Newest First', 'Most Active', 'Alphabetical'];
|
||||
|
||||
const RESULTS = [
|
||||
{
|
||||
type: 'Project',
|
||||
badgeClass: 'pub-badge-open',
|
||||
badgeIcon: 'fa-flask',
|
||||
badgeLabel: 'Active Project',
|
||||
statusClass: 'pub-badge-peer',
|
||||
statusLabel: 'Environmental Studies',
|
||||
title: 'Urban Microclimate Modeling',
|
||||
lead: 'Dr. Alan Turing',
|
||||
updated: 'Updated 2 days ago',
|
||||
center: 'Institute for Climate Research',
|
||||
desc: 'Developing high-resolution predictive models for heat island effects in European metropolitan areas using machine learning and satellite data.',
|
||||
tags: ['Climate', 'Machine Learning', 'Urban Studies'],
|
||||
progress: 65,
|
||||
},
|
||||
{
|
||||
type: 'Lab',
|
||||
badgeClass: 'pub-badge-institutional',
|
||||
badgeIcon: 'fa-building-user',
|
||||
badgeLabel: 'Research Lab',
|
||||
statusClass: 'pub-badge-peer',
|
||||
statusLabel: 'Cognitive Science',
|
||||
title: 'Cognitive Sciences Lab',
|
||||
lead: 'Prof. Marie Curie',
|
||||
updated: 'Updated 1 week ago',
|
||||
center: 'Center for Digital Humanities',
|
||||
desc: 'Exploring the intersection of artificial intelligence and human psychology, with a focus on decision-making processes and behavioral modeling.',
|
||||
tags: ['AI', 'Psychology', 'Neuroscience'],
|
||||
progress: null,
|
||||
},
|
||||
{
|
||||
type: 'Project',
|
||||
badgeClass: 'pub-badge-request',
|
||||
badgeIcon: 'fa-gavel',
|
||||
badgeLabel: 'Data Collection',
|
||||
statusClass: 'pub-badge-peer',
|
||||
statusLabel: 'Law & Policy',
|
||||
title: 'Digital Rights in the EU Framework',
|
||||
lead: 'Dr. Elena Rostova',
|
||||
updated: 'Updated 1 week ago',
|
||||
center: 'Institute for Advanced European Studies',
|
||||
desc: 'A comparative analysis of member state implementation of digital privacy directives and their impact on civil liberties across the EU.',
|
||||
tags: ['Digital Rights', 'EU Law', 'Privacy'],
|
||||
progress: 30,
|
||||
},
|
||||
];
|
||||
|
||||
const ResearchSearchResults = () => {
|
||||
const [isSortOpen, setIsSortOpen] = useState(false);
|
||||
const [selectedSort, setSelectedSort] = useState('Relevance');
|
||||
|
||||
return (
|
||||
<div className="pub-results">
|
||||
|
||||
{/* Toolbar */}
|
||||
<div className="pub-results-toolbar">
|
||||
<p className="pub-results-count">
|
||||
Showing <strong>1–10</strong> of <strong>340</strong> results
|
||||
</p>
|
||||
<div className="pub-sort-wrap">
|
||||
<label>Sort by:</label>
|
||||
<div className="pub-sort-dropdown">
|
||||
<button
|
||||
className={`pub-sort-dropdown-btn ${isSortOpen ? 'open' : ''}`}
|
||||
onClick={() => setIsSortOpen(!isSortOpen)}
|
||||
>
|
||||
<span>{selectedSort}</span>
|
||||
<i className="fa-solid fa-chevron-down"></i>
|
||||
</button>
|
||||
{isSortOpen && (
|
||||
<div className="pub-sort-dropdown-menu">
|
||||
{SORT_OPTIONS.map((opt) => (
|
||||
<div
|
||||
key={opt}
|
||||
className={`pub-sort-dropdown-option ${selectedSort === opt ? 'selected' : ''}`}
|
||||
onClick={() => { setSelectedSort(opt); setIsSortOpen(false); }}
|
||||
>
|
||||
{opt}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Result cards */}
|
||||
<div className="pub-card-list">
|
||||
{RESULTS.map((item, idx) => (
|
||||
<div key={idx} className="pub-card">
|
||||
<div className="pub-card-top">
|
||||
<h3 className="pub-card-title">
|
||||
<a href="#">{item.title}</a>
|
||||
</h3>
|
||||
<div className="pub-badges">
|
||||
<span className={`pub-badge ${item.badgeClass}`}>
|
||||
<i className={`fa-solid ${item.badgeIcon}`}></i> {item.badgeLabel}
|
||||
</span>
|
||||
<span className="pub-badge pub-badge-peer">{item.statusLabel}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pub-card-meta">
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-solid fa-user"></i>
|
||||
<strong>{item.lead}</strong>
|
||||
</div>
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-regular fa-clock"></i> {item.updated}
|
||||
</div>
|
||||
<div className="pub-meta-item">
|
||||
<i className="fa-solid fa-building-columns"></i> {item.center}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="pub-card-abstract">{item.desc}</p>
|
||||
|
||||
<div className="pub-keywords">
|
||||
<span className="pub-keywords-label">Tags:</span>
|
||||
{item.tags.map((tag) => (
|
||||
<span key={tag} className="pub-keyword-tag">{tag}</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{item.progress !== null && (
|
||||
<div style={{ marginBottom: '1rem' }}>
|
||||
<div className="flex justify-between text-xs mb-1" style={{ color: 'var(--pub-muted)' }}>
|
||||
<span>Progress</span>
|
||||
<span style={{ fontWeight: 600, color: 'var(--pub-text)' }}>{item.progress}%</span>
|
||||
</div>
|
||||
<div style={{ width: '100%', height: '6px', backgroundColor: 'var(--pub-bg)', borderRadius: '9999px' }}>
|
||||
<div style={{ width: `${item.progress}%`, height: '6px', backgroundColor: 'var(--pub-blue)', borderRadius: '9999px' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="pub-card-actions">
|
||||
<button className="pub-action-btn pub-action-btn-primary">
|
||||
<i className="fa-solid fa-arrow-right"></i> View Details
|
||||
</button>
|
||||
<button className="pub-action-btn pub-action-btn-secondary">
|
||||
<i className="fa-regular fa-bookmark"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Pagination */}
|
||||
<div className="pub-pagination">
|
||||
<button className="pub-page-btn" disabled>
|
||||
<i className="fa-solid fa-arrow-left"></i> Previous
|
||||
</button>
|
||||
<div className="pub-page-numbers">
|
||||
<button className="pub-page-num active">1</button>
|
||||
<button className="pub-page-num">2</button>
|
||||
<button className="pub-page-num">3</button>
|
||||
<span className="pub-page-ellipsis">...</span>
|
||||
<button className="pub-page-num">34</button>
|
||||
</div>
|
||||
<button className="pub-page-btn">
|
||||
Next <i className="fa-solid fa-arrow-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResearchSearchResults;
|
||||
94
app/components/research/search/ResearchSearchSidebar.tsx
Normal file
94
app/components/research/search/ResearchSearchSidebar.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const DOMAINS = ['Law & Policy (42)', 'Cognitive Science (28)', 'Environmental Studies (35)', 'History & Humanities (50)', 'Economics (19)'];
|
||||
const STATUSES = ['Active', 'Data Collection', 'Review', 'Completed'];
|
||||
const TYPES = ['Researchers', 'Labs', 'Projects', 'Institutes'];
|
||||
|
||||
const AccordionSection = ({
|
||||
title,
|
||||
open,
|
||||
onToggle,
|
||||
children,
|
||||
}: {
|
||||
title: string;
|
||||
open: boolean;
|
||||
onToggle: () => void;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<div className="pub-accordion-item">
|
||||
<button
|
||||
className={`pub-accordion-trigger ${open ? 'open' : ''}`}
|
||||
onClick={onToggle}
|
||||
>
|
||||
{title}
|
||||
<i className="fa-solid fa-chevron-down"></i>
|
||||
</button>
|
||||
<div className={`pub-accordion-body ${open ? 'open' : ''}`}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const ResearchSearchSidebar = () => {
|
||||
const [isDomainOpen, setIsDomainOpen] = useState(true);
|
||||
const [isStatusOpen, setIsStatusOpen] = useState(true);
|
||||
const [isTypeOpen, setIsTypeOpen] = useState(true);
|
||||
|
||||
return (
|
||||
<aside className="pub-sidebar">
|
||||
<div className="pub-sidebar-inner">
|
||||
|
||||
<div className="pub-sidebar-header">
|
||||
<h2>
|
||||
<i className="fa-solid fa-filter"></i> Filters
|
||||
</h2>
|
||||
<button className="pub-clear-btn">Clear All</button>
|
||||
</div>
|
||||
|
||||
<div className="pub-accordion">
|
||||
|
||||
{/* Research Domain */}
|
||||
<AccordionSection title="Research Domain" open={isDomainOpen} onToggle={() => setIsDomainOpen(!isDomainOpen)}>
|
||||
<div className="pub-filter-list">
|
||||
{DOMAINS.map((d, i) => (
|
||||
<label key={d} className="pub-filter-label">
|
||||
<input type="checkbox" className="pub-checkbox" defaultChecked={i === 0} />
|
||||
<span>{d}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</AccordionSection>
|
||||
|
||||
{/* Project Status */}
|
||||
<AccordionSection title="Project Status" open={isStatusOpen} onToggle={() => setIsStatusOpen(!isStatusOpen)}>
|
||||
<div className="pub-filter-list">
|
||||
{STATUSES.map((s) => (
|
||||
<label key={s} className="pub-filter-label">
|
||||
<input type="checkbox" className="pub-checkbox" />
|
||||
<span>{s}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</AccordionSection>
|
||||
|
||||
{/* Type */}
|
||||
<AccordionSection title="Type" open={isTypeOpen} onToggle={() => setIsTypeOpen(!isTypeOpen)}>
|
||||
<div className="pub-filter-list">
|
||||
{TYPES.map((t) => (
|
||||
<label key={t} className="pub-filter-label">
|
||||
<input type="checkbox" className="pub-checkbox" />
|
||||
<span>{t}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</AccordionSection>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResearchSearchSidebar;
|
||||
Reference in New Issue
Block a user