forked from UKSOURCE/hailearning.edu.vn
feat: add Contact and Accreditation pages
This commit is contained in:
53
app/accreditation/accreditation.css
Normal file
53
app/accreditation/accreditation.css
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* ============================================
|
||||||
|
Accreditation Page — Scoped Styles
|
||||||
|
Scope: .accreditation-page
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Typography — dùng div thay h1/h2/h3 */
|
||||||
|
.accreditation-page .acc-heading {
|
||||||
|
font-size: clamp(2.5rem, 5vw, 3.75rem);
|
||||||
|
line-height: 1.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accreditation-page .acc-section-title {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accreditation-page .acc-card-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Color tokens ---------- */
|
||||||
|
.accreditation-page .text-brand-blue { color: #1b254b; }
|
||||||
|
.accreditation-page .bg-brand-blue { background-color: #1b254b; }
|
||||||
|
.accreditation-page .bg-brand-light { background-color: #f8fbff; }
|
||||||
|
.accreditation-page .bg-brand-accent { background-color: #3b82f6; }
|
||||||
|
.accreditation-page .text-brand-accent { color: #3b82f6; }
|
||||||
|
.accreditation-page .text-ui-text { color: #111827; }
|
||||||
|
.accreditation-page .text-ui-muted { color: #6b7280; }
|
||||||
|
.accreditation-page .bg-ui-bg { background-color: #f9fafb; }
|
||||||
|
.accreditation-page .border-ui-border { border-color: #e5e7eb; }
|
||||||
|
|
||||||
|
/* ---------- Shadow tokens ---------- */
|
||||||
|
.accreditation-page .shadow-soft {
|
||||||
|
box-shadow: 0 1px 3px rgb(0 0 0 / 0.06), 0 1px 2px rgb(0 0 0 / 0.04);
|
||||||
|
}
|
||||||
|
.accreditation-page .shadow-hover,
|
||||||
|
.accreditation-page .hover\:shadow-hover:hover {
|
||||||
|
box-shadow: 0 8px 24px rgb(0 0 0 / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Border radius fix ---------- */
|
||||||
|
.accreditation-page .rounded-\[24px\] { border-radius: 24px !important; }
|
||||||
|
.accreditation-page .rounded-lg { border-radius: 8px !important; }
|
||||||
|
.accreditation-page .rounded-md { border-radius: 6px !important; }
|
||||||
|
|
||||||
|
/* Mesh background gradient */
|
||||||
|
.accreditation-page .mesh-bg {
|
||||||
|
background: linear-gradient(135deg, #f0f4ff 0%, #e8f0fe 40%, #ffffff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rounded-xl fix */
|
||||||
|
.accreditation-page .rounded-xl { border-radius: 12px !important; }
|
||||||
14
app/accreditation/page.tsx
Normal file
14
app/accreditation/page.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import "./accreditation.css";
|
||||||
|
import AccreditationHero from "../components/accreditation/AccreditationHero";
|
||||||
|
import AccreditationGrid from "../components/accreditation/AccreditationGrid";
|
||||||
|
import QualityStandards from "../components/accreditation/QualityStandards";
|
||||||
|
|
||||||
|
export default function AccreditationPage() {
|
||||||
|
return (
|
||||||
|
<main className="accreditation-page w-full">
|
||||||
|
<AccreditationHero />
|
||||||
|
<AccreditationGrid />
|
||||||
|
<QualityStandards />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
20
app/components/accreditation/AccreditationCard.tsx
Normal file
20
app/components/accreditation/AccreditationCard.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
type AccreditationCardProps = {
|
||||||
|
logo: string;
|
||||||
|
logoAlt: string;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AccreditationCard({ logo, logoAlt, title, subtitle, description }: AccreditationCardProps) {
|
||||||
|
return (
|
||||||
|
<div className="bg-white p-8 rounded-[24px] shadow-soft border border-ui-border hover:shadow-hover transition-all duration-300">
|
||||||
|
<div className="h-20 flex items-center mb-6">
|
||||||
|
<img src={logo} alt={logoAlt} className="h-16 object-contain grayscale hover:grayscale-0 transition-all duration-300" />
|
||||||
|
</div>
|
||||||
|
<div className="acc-card-title font-bold text-ui-text mb-2">{title}</div>
|
||||||
|
<p className="text-sm text-brand-accent font-medium mb-4">{subtitle}</p>
|
||||||
|
<p className="text-ui-muted leading-relaxed text-sm">{description}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
43
app/components/accreditation/AccreditationGrid.tsx
Normal file
43
app/components/accreditation/AccreditationGrid.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import AccreditationCard from "./AccreditationCard";
|
||||||
|
|
||||||
|
const accreditations = [
|
||||||
|
{
|
||||||
|
logo: "https://storage.googleapis.com/uxpilot-auth.appspot.com/5688d070b4-3c6c0b3c66f21c272558.png",
|
||||||
|
logoAlt: "French Ministry of Higher Education Logo",
|
||||||
|
title: "Ministère de l'Enseignement Supérieur",
|
||||||
|
subtitle: "National Institutional Accreditation",
|
||||||
|
description: "Fully recognized by the French government as a degree-granting institution, ensuring our diplomas meet national educational standards.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
logo: "https://storage.googleapis.com/uxpilot-auth.appspot.com/e2bd5be26e-fb4f2f04e138848db7e4.png",
|
||||||
|
logoAlt: "European Association for Quality Assurance Logo",
|
||||||
|
title: "ENQA",
|
||||||
|
subtitle: "European Quality Assurance",
|
||||||
|
description: "Compliant with the Standards and Guidelines for Quality Assurance in the European Higher Education Area (ESG).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
logo: "https://storage.googleapis.com/uxpilot-auth.appspot.com/b97d101d24-d2eeb52206ef7f99965a.png",
|
||||||
|
logoAlt: "Global Liberal Arts Alliance Logo",
|
||||||
|
title: "GLAA",
|
||||||
|
subtitle: "International Programmatic Certification",
|
||||||
|
description: "Certified member of the Global Liberal Arts Alliance, affirming our commitment to interdisciplinary education globally.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function AccreditationGrid() {
|
||||||
|
return (
|
||||||
|
<section id="accreditation-grid" className="py-20 bg-ui-bg">
|
||||||
|
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||||
|
<div className="mb-12">
|
||||||
|
<div className="acc-section-title font-bold text-ui-text mb-4">Recognized Issuing Bodies</div>
|
||||||
|
<p className="text-ui-muted text-lg">Our institutional and programmatic accreditations ensure global recognition of our degrees.</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
{accreditations.map((item) => (
|
||||||
|
<AccreditationCard key={item.title} {...item} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
22
app/components/accreditation/AccreditationHero.tsx
Normal file
22
app/components/accreditation/AccreditationHero.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
export default function AccreditationHero() {
|
||||||
|
return (
|
||||||
|
<section id="accreditation-hero" className="relative w-full py-20 lg:py-24 bg-white overflow-hidden mesh-bg border-b border-ui-border">
|
||||||
|
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||||
|
<div className="text-center max-w-4xl mx-auto">
|
||||||
|
<div className="inline-flex items-center gap-2 mb-6">
|
||||||
|
<span className="w-8 h-[2px] bg-brand-accent"></span>
|
||||||
|
<span className="text-sm font-semibold text-brand-blue uppercase tracking-wider">Global Standards </span>
|
||||||
|
<span className="w-8 h-[2px] bg-brand-accent"></span>
|
||||||
|
</div>
|
||||||
|
<div className="acc-heading font-bold text-brand-blue leading-tight mb-6">
|
||||||
|
Accreditations <br />
|
||||||
|
<span className="text-ui-text">& Compliance</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-lg text-ui-muted leading-relaxed mb-8">
|
||||||
|
Our commitment to excellence is validated by leading national and international accrediting bodies. We uphold the highest standards of academic rigor, research ethics, and institutional quality.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
71
app/components/accreditation/QualityStandards.tsx
Normal file
71
app/components/accreditation/QualityStandards.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
const features = [
|
||||||
|
{
|
||||||
|
icon: "fa-solid fa-chart-line",
|
||||||
|
title: "Continuous Evaluation",
|
||||||
|
description: "Annual reviews of all academic programs by independent academic boards.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-solid fa-users",
|
||||||
|
title: "Peer Review Integration",
|
||||||
|
description: "Regular assessments conducted by visiting professors from partner institutions.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fa-solid fa-shield",
|
||||||
|
title: "Ethical Compliance",
|
||||||
|
description: "Strict adherence to international research ethics and data protection standards.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function QualityStandards() {
|
||||||
|
return (
|
||||||
|
<section id="quality-standards" className="py-20 bg-white border-t border-ui-border">
|
||||||
|
<div className="max-w-[1440px] mx-auto px-6 lg:px-8">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
|
||||||
|
|
||||||
|
{/* Left: Text content */}
|
||||||
|
<div className="space-y-8">
|
||||||
|
<div className="inline-flex items-center gap-2">
|
||||||
|
<span className="w-8 h-[2px] bg-brand-accent"></span>
|
||||||
|
<span className="text-sm font-semibold text-ui-muted uppercase tracking-wider">Quality Assurance</span>
|
||||||
|
</div>
|
||||||
|
<div className="acc-section-title font-bold text-ui-text">Our Framework for Excellence</div>
|
||||||
|
<p className="text-lg text-ui-muted leading-relaxed">
|
||||||
|
Our internal quality assurance mechanisms are designed to continuously evaluate and improve our academic offerings, research outputs, and student services.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="space-y-6 mt-8">
|
||||||
|
{features.map((f) => (
|
||||||
|
<div key={f.title} className="flex gap-4">
|
||||||
|
<div className="w-12 h-12 rounded-xl bg-brand-light flex items-center justify-center text-brand-blue shrink-0">
|
||||||
|
<i className={`${f.icon} text-xl`}></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="acc-card-title font-bold text-ui-text mb-1">{f.title}</div>
|
||||||
|
<p className="text-ui-muted text-sm">{f.description}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right: Images */}
|
||||||
|
<div className="relative">
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<img
|
||||||
|
className="w-full h-64 object-cover rounded-[24px] shadow-soft"
|
||||||
|
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/a45c3de13a-8173142c33595269388d.png"
|
||||||
|
alt="Students studying in library"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
className="w-full h-64 object-cover rounded-[24px] shadow-soft mt-8"
|
||||||
|
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/cb66207ea0-16795a67db08ef0e6f8c.png"
|
||||||
|
alt="Research facility"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
21
app/components/contactus/Accessibility.tsx
Normal file
21
app/components/contactus/Accessibility.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export default function Accessibility() {
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-[24px] p-8 shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-gray-100">
|
||||||
|
<div className="contact-card-title font-bold text-dark mb-4">Accessibility</div>
|
||||||
|
<p className="text-sm text-gray-600 mb-3 mt-2">
|
||||||
|
Our campus is designed to be accessible to everyone. If you require specific accommodations for your visit, please contact us in advance.
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-3">
|
||||||
|
<div className="px-4 py-2 bg-gray-50 border border-gray-200 rounded-full text-xs font-medium text-gray-600 flex items-center gap-2">
|
||||||
|
<i className="fa-brands fa-accessible-icon text-primary"></i> Wheelchair Access
|
||||||
|
</div>
|
||||||
|
<div className="px-4 py-2 bg-gray-50 border border-gray-200 rounded-full text-xs font-medium text-gray-600 flex items-center gap-2">
|
||||||
|
<i className="fa-solid fa-elevator text-primary"></i> Elevators
|
||||||
|
</div>
|
||||||
|
<div className="px-4 py-2 bg-gray-50 border border-gray-200 rounded-full text-xs font-medium text-gray-600 flex items-center gap-2">
|
||||||
|
<i className="fa-solid fa-square-parking text-primary"></i> Reserved Parking
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
app/components/contactus/ContactHero.tsx
Normal file
17
app/components/contactus/ContactHero.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export default function ContactHero() {
|
||||||
|
return (
|
||||||
|
<section id="contact-hero" className="bg-white border-b border-gray-200 pt-16 pb-20 px-6 lg:px-12">
|
||||||
|
<div className="max-w-[1440px] mx-auto text-center">
|
||||||
|
<span className="inline-block bg-blue-50 text-xs font-bold px-4 py-2 uppercase tracking-wider rounded-full mb-3 border border-blue-100" style={{ color: "rgb(38, 60, 111)" }}>
|
||||||
|
Get in Touch
|
||||||
|
</span>
|
||||||
|
<div className="contact-heading font-display font-bold text-dark mb-6 leading-tight max-w-3xl mx-auto">
|
||||||
|
How can we help advance your research journey?
|
||||||
|
</div>
|
||||||
|
<p className="text-gray-600 text-lg mb-0 leading-relaxed max-w-2xl mx-auto">
|
||||||
|
Connect with our specialized departments to find the support, guidance, and resources you need to succeed at Paris Research University.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
app/components/contactus/ContactSplit.tsx
Normal file
19
app/components/contactus/ContactSplit.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import InquiryForm from "./InquiryForm";
|
||||||
|
import LocationMap from "./LocationMap";
|
||||||
|
import OfficeHours from "./OfficeHours";
|
||||||
|
import Accessibility from "./Accessibility";
|
||||||
|
|
||||||
|
export default function ContactSplit() {
|
||||||
|
return (
|
||||||
|
<section id="inquiry-form-section" className="py-16 px-6 lg:px-12 max-w-[1440px] mx-auto">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-stretch">
|
||||||
|
<InquiryForm />
|
||||||
|
<div className="space-y-8">
|
||||||
|
<LocationMap />
|
||||||
|
<OfficeHours />
|
||||||
|
<Accessibility />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/components/contactus/DepartmentCard.tsx
Normal file
27
app/components/contactus/DepartmentCard.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
type DepartmentCardProps = {
|
||||||
|
icon: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function DepartmentCard({ icon, title, description, email, phone }: DepartmentCardProps) {
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-[16px] p-8 shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-gray-100 hover:shadow-[0_8px_30px_rgb(38,60,111,0.08)] transition-all duration-300 flex flex-col h-full group">
|
||||||
|
<div className="w-14 h-14 bg-blue-50 rounded-[12px] flex items-center justify-center text-primary text-2xl mb-6 group-hover:bg-primary group-hover:text-white transition-colors">
|
||||||
|
<i className={icon}></i>
|
||||||
|
</div>
|
||||||
|
<div className="contact-card-title font-display font-bold text-dark mb-3">{title}</div>
|
||||||
|
<p className="text-sm text-gray-600 mb-6 flex-grow">{description}</p>
|
||||||
|
<div className="pt-4 border-t border-gray-100 mt-auto">
|
||||||
|
<a href={`mailto:${email}`} className="flex items-center gap-3 text-sm text-gray-700 hover:text-primary mb-3 transition-colors">
|
||||||
|
<i className="far fa-envelope text-primary w-4"></i> {email}
|
||||||
|
</a>
|
||||||
|
<a href={`tel:${phone.replace(/\s/g, '')}`} className="flex items-center gap-3 text-sm text-gray-700 hover:text-primary transition-colors">
|
||||||
|
<i className="fas fa-phone text-primary w-4"></i> {phone}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
22
app/components/contactus/DepartmentCardBlue.tsx
Normal file
22
app/components/contactus/DepartmentCardBlue.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
export default function DepartmentCardBlue() {
|
||||||
|
return (
|
||||||
|
<div className="bg-primary text-white rounded-[16px] p-8 shadow-[0_8px_30px_rgb(38,60,111,0.15)] transition-all duration-300 flex flex-col h-full relative overflow-hidden">
|
||||||
|
<div className="absolute top-0 right-0 w-32 h-32 bg-white/5 rounded-full -mr-10 -mt-10 blur-xl"></div>
|
||||||
|
<div className="w-14 h-14 bg-white/10 rounded-[12px] flex items-center justify-center text-white text-2xl mb-6 backdrop-blur-sm border border-white/20">
|
||||||
|
<i className="fas fa-microscope"></i>
|
||||||
|
</div>
|
||||||
|
<div className="contact-card-title font-display font-bold mb-3">Research Office</div>
|
||||||
|
<p className="text-sm text-white/80 mb-6 flex-grow relative z-10">
|
||||||
|
Grant applications, ethics committee approvals, lab space allocation, and cross-disciplinary collaboration opportunities.
|
||||||
|
</p>
|
||||||
|
<div className="pt-4 border-t border-white/20 mt-auto relative z-10">
|
||||||
|
<a href="mailto:research@parisresearch.edu" className="flex items-center gap-3 text-sm text-white/90 hover:text-white mb-3 transition-colors">
|
||||||
|
<i className="far fa-envelope w-4 opacity-80"></i> research@parisresearch.edu
|
||||||
|
</a>
|
||||||
|
<a href="tel:+33123456790" className="flex items-center gap-3 text-sm text-white/90 hover:text-white transition-colors">
|
||||||
|
<i className="fas fa-phone w-4 opacity-80"></i> +33 1 23 45 67 90
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
app/components/contactus/DepartmentCardEmpty.tsx
Normal file
16
app/components/contactus/DepartmentCardEmpty.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export default function DepartmentCardEmpty() {
|
||||||
|
return (
|
||||||
|
<div className="bg-gray-50 rounded-[16px] p-8 border border-gray-200 border-dashed flex flex-col items-center justify-center text-center h-full">
|
||||||
|
<div className="w-16 h-16 bg-white rounded-full flex items-center justify-center text-gray-400 text-2xl mb-4 shadow-sm">
|
||||||
|
<i className="fas fa-circle-question"></i>
|
||||||
|
</div>
|
||||||
|
<div className="contact-card-title font-bold text-gray-700 mb-2">Not sure who to contact?</div>
|
||||||
|
<p className="text-sm text-gray-500 mb-6">
|
||||||
|
Use our general inquiry form below and we'll route your message to the appropriate department.
|
||||||
|
</p>
|
||||||
|
<a href="#inquiry-form-section" className="text-primary font-medium text-sm hover:underline flex items-center gap-2">
|
||||||
|
Go to Form <i className="fas fa-arrow-down"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
49
app/components/contactus/DepartmentDirectory.tsx
Normal file
49
app/components/contactus/DepartmentDirectory.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import DepartmentCard from "./DepartmentCard";
|
||||||
|
import DepartmentCardBlue from "./DepartmentCardBlue";
|
||||||
|
import DepartmentCardEmpty from "./DepartmentCardEmpty";
|
||||||
|
|
||||||
|
const departments = [
|
||||||
|
{
|
||||||
|
icon: "fas fa-graduation-cap",
|
||||||
|
title: "Admissions & Enrollment",
|
||||||
|
description: "Questions regarding application processes, deadlines, program requirements, and international student visas.",
|
||||||
|
email: "admissions@parisresearch.edu",
|
||||||
|
phone: "+33 1 23 45 67 89",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fas fa-handshake",
|
||||||
|
title: "Industry Partnerships",
|
||||||
|
description: "Corporate sponsorships, technology transfer, joint research ventures, and industry-funded scholarships.",
|
||||||
|
email: "partners@parisresearch.edu",
|
||||||
|
phone: "+33 1 23 45 67 91",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fas fa-bullhorn",
|
||||||
|
title: "Media & Press",
|
||||||
|
description: "Press releases, expert commentary requests, media kits, and institutional branding guidelines.",
|
||||||
|
email: "press@parisresearch.edu",
|
||||||
|
phone: "+33 1 23 45 67 92",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "fas fa-book-open",
|
||||||
|
title: "Repository Support",
|
||||||
|
description: "Assistance with navigating the publication database, requesting access to restricted papers, and submitting new works.",
|
||||||
|
email: "library@parisresearch.edu",
|
||||||
|
phone: "+33 1 23 45 67 93",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function DepartmentDirectory() {
|
||||||
|
return (
|
||||||
|
<section id="department-directory" className="py-20 px-6 lg:px-12 max-w-[1440px] mx-auto -mt-10 relative z-10">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<DepartmentCard {...departments[0]} />
|
||||||
|
<DepartmentCardBlue />
|
||||||
|
<DepartmentCard {...departments[1]} />
|
||||||
|
<DepartmentCard {...departments[2]} />
|
||||||
|
<DepartmentCard {...departments[3]} />
|
||||||
|
<DepartmentCardEmpty />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
71
app/components/contactus/InquiryForm.tsx
Normal file
71
app/components/contactus/InquiryForm.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
export default function InquiryForm() {
|
||||||
|
const inputClass = "w-full bg-gray-50 border border-gray-200 text-gray-800 px-4 py-3 rounded-[12px] focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all text-sm placeholder:text-gray-400";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-[24px] p-8 md:p-10 shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-gray-100 h-full flex flex-col">
|
||||||
|
<div className="mb-8">
|
||||||
|
<div className="contact-form-title font-display font-bold text-dark mb-1">Send a Message</div>
|
||||||
|
<p className="text-gray-600 text-sm">Please fill out the form below and our team will get back to you within 24-48 business hours.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form className="space-y-5 flex-1 flex flex-col">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium text-gray-700 block">First Name</label>
|
||||||
|
<input type="text" placeholder="Jane" className={inputClass} />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium text-gray-700 block">Last Name</label>
|
||||||
|
<input type="text" placeholder="Doe" className={inputClass} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium text-gray-700 block">Email Address <span className="text-red-500">*</span></label>
|
||||||
|
<input type="email" placeholder="jane.doe@example.com" required className={inputClass} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium text-gray-700 block">Inquiry Topic <span className="text-red-500">*</span></label>
|
||||||
|
<div className="relative">
|
||||||
|
<select required className={inputClass + " appearance-none cursor-pointer"}>
|
||||||
|
<option value="" disabled selected>Select a topic...</option>
|
||||||
|
<option value="admissions">Admissions & Enrollment</option>
|
||||||
|
<option value="research">Research Opportunities</option>
|
||||||
|
<option value="partnerships">Corporate Partnerships</option>
|
||||||
|
<option value="media">Media Inquiry</option>
|
||||||
|
<option value="repository">Publication Repository Access</option>
|
||||||
|
<option value="other">Other</option>
|
||||||
|
</select>
|
||||||
|
<div className="absolute inset-y-0 right-0 flex items-center px-4 pointer-events-none text-gray-500">
|
||||||
|
<i className="fas fa-chevron-down text-xs"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<label className="text-sm font-medium text-gray-700 block">Message <span className="text-red-500">*</span></label>
|
||||||
|
<textarea rows={5} placeholder="How can we help you?" required className={inputClass + " resize-none"} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pt-2 pb-2 space-y-4">
|
||||||
|
<label className="flex items-start gap-3 cursor-pointer">
|
||||||
|
<input type="checkbox" required className="custom-checkbox mt-1 shrink-0" />
|
||||||
|
<span className="text-xs text-gray-600 leading-relaxed">
|
||||||
|
I consent to having Paris Research University collect my details via this form to respond to my inquiry. I understand my data will be handled in accordance with the{" "}
|
||||||
|
<a href="#" className="text-primary hover:underline">Privacy Policy</a>.
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="bg-gray-50 p-4 rounded-[12px] border border-gray-200 flex items-center justify-between max-w-xs">
|
||||||
|
<span className="text-sm text-gray-600 font-medium">I am human</span>
|
||||||
|
<input type="checkbox" required className="custom-checkbox w-6 h-6 rounded-full border-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" className="w-full bg-primary text-white font-bold py-4 rounded-[12px] text-sm hover:bg-opacity-90 transition-colors shadow-md flex items-center justify-center gap-2">
|
||||||
|
Send Message <i className="fas fa-paper-plane text-xs"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
app/components/contactus/LocationMap.tsx
Normal file
26
app/components/contactus/LocationMap.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export default function LocationMap() {
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-[24px] overflow-hidden shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-gray-100 h-[420px] relative">
|
||||||
|
<div className="absolute inset-0 bg-gray-200 relative">
|
||||||
|
<img
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
src="https://storage.googleapis.com/uxpilot-auth.appspot.com/3d6faeb2c9-8e1cfd08c74433d49f78.png"
|
||||||
|
alt="Modern minimalist map of Paris showing a university campus location with a blue pin marker"
|
||||||
|
/>
|
||||||
|
{/* Floating Pin Card */}
|
||||||
|
<div className="absolute bottom-6 left-6 right-6 bg-white/95 backdrop-blur-md p-4 rounded-[12px] shadow-lg border border-white/50 flex items-start gap-4">
|
||||||
|
<div className="w-10 h-10 bg-blue-50 rounded-full flex items-center justify-center text-primary flex-shrink-0 mt-1">
|
||||||
|
<i className="fas fa-location-dot"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="contact-pin-title font-bold text-dark mb-1">Main Campus</div>
|
||||||
|
<p className="text-xs text-gray-600 leading-relaxed">
|
||||||
|
15 Rue de l'École de Médecine<br />75006 Paris, France
|
||||||
|
</p>
|
||||||
|
<a href="#" className="text-primary text-xs font-medium mt-2 inline-block hover:underline">Get Directions</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
28
app/components/contactus/OfficeHours.tsx
Normal file
28
app/components/contactus/OfficeHours.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
const hours = [
|
||||||
|
{ day: "Monday - Thursday", time: "08:30 - 18:00" },
|
||||||
|
{ day: "Friday", time: "08:30 - 17:00" },
|
||||||
|
{ day: "Saturday - Sunday", time: null },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function OfficeHours() {
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-[24px] p-10 shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-gray-100">
|
||||||
|
<div className="flex items-center gap-3 mb-6">
|
||||||
|
<i className="far fa-clock text-primary text-xl"></i>
|
||||||
|
<div className="contact-card-title font-display font-bold text-dark" style={{ fontSize: "1.3rem" }}>Office Hours</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{hours.map(({ day, time }) => (
|
||||||
|
<div key={day} className="flex justify-between items-center pb-3 border-b border-gray-100 text-sm">
|
||||||
|
<span className="text-gray-600 font-medium">{day}</span>
|
||||||
|
{time
|
||||||
|
? <span className="text-dark font-bold">{time}</span>
|
||||||
|
: <span className="text-gray-400 font-medium">Closed</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
159
app/contactus/contact.css
Normal file
159
app/contactus/contact.css
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/* ============================================
|
||||||
|
Contact Page — Scoped Styles
|
||||||
|
Scope: .contact-page
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&display=swap');
|
||||||
|
|
||||||
|
/* Reset heading override từ main.css */
|
||||||
|
.contact-page h1,
|
||||||
|
.contact-page h2,
|
||||||
|
.contact-page h3,
|
||||||
|
.contact-page h4 {
|
||||||
|
font-size: unset;
|
||||||
|
font-weight: unset;
|
||||||
|
line-height: unset;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
.contact-page .contact-heading {
|
||||||
|
font-family: 'Playfair Display', serif;
|
||||||
|
font-size: clamp(2rem, 4vw, 3.5rem);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-page .contact-card-title {
|
||||||
|
font-family: 'Playfair Display', serif;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-page .contact-form-title {
|
||||||
|
font-family: 'Playfair Display', serif;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-page .contact-pin-title {
|
||||||
|
font-family: 'Playfair Display', serif;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color token: --primary */
|
||||||
|
.contact-page .text-primary,
|
||||||
|
.contact-page .hover\:text-primary:hover { color: rgb(38, 60, 111); }
|
||||||
|
|
||||||
|
.contact-page .bg-primary { background-color: rgb(38, 60, 111) !important; }
|
||||||
|
|
||||||
|
.contact-page .border-primary { border-color: rgb(38, 60, 111); }
|
||||||
|
|
||||||
|
.contact-page .focus\:border-primary:focus { border-color: rgb(38, 60, 111); }
|
||||||
|
.contact-page .focus\:ring-primary:focus { --tw-ring-color: rgb(38, 60, 111); }
|
||||||
|
|
||||||
|
/* group-hover bg-primary */
|
||||||
|
.contact-page .group:hover .group-hover\:bg-primary { background-color: rgb(38, 60, 111) !important; }
|
||||||
|
.contact-page .group:hover .group-hover\:text-white { color: #fff; }
|
||||||
|
|
||||||
|
/* Color token: --dark */
|
||||||
|
.contact-page .text-dark { color: #111827; }
|
||||||
|
|
||||||
|
/* bg-white/5, /10 */
|
||||||
|
.contact-page .bg-white\/5 { background-color: rgba(255,255,255,0.05); }
|
||||||
|
.contact-page .bg-white\/10 { background-color: rgba(255,255,255,0.10); }
|
||||||
|
|
||||||
|
/* border-white/20, /50 */
|
||||||
|
.contact-page .border-white\/20 { border-color: rgba(255,255,255,0.20); }
|
||||||
|
.contact-page .border-white\/50 { border-color: rgba(255,255,255,0.50); }
|
||||||
|
|
||||||
|
/* text-white/80, /90 */
|
||||||
|
.contact-page .text-white\/80 { color: rgba(255,255,255,0.80); }
|
||||||
|
.contact-page .text-white\/90 { color: rgba(255,255,255,0.90); }
|
||||||
|
|
||||||
|
/* bg-white/95 */
|
||||||
|
.contact-page .bg-white\/95 { background-color: rgba(255,255,255,0.95); }
|
||||||
|
|
||||||
|
/* border-t border-white/20 */
|
||||||
|
.contact-page .border-white\/20 { border-color: rgba(255,255,255,0.20); }
|
||||||
|
|
||||||
|
/* rounded fixes — main.css có thể reset border-radius */
|
||||||
|
.contact-page .rounded-\[16px\] { border-radius: 16px !important; }
|
||||||
|
.contact-page .rounded-\[24px\] { border-radius: 24px !important; }
|
||||||
|
.contact-page .rounded-\[12px\] { border-radius: 12px !important; }
|
||||||
|
.contact-page .rounded-full { border-radius: 9999px !important; }
|
||||||
|
.contact-page .rounded-\[12px\] { border-radius: 12px !important; }
|
||||||
|
|
||||||
|
/* button reset */
|
||||||
|
.contact-page button,
|
||||||
|
.contact-page input,
|
||||||
|
.contact-page select,
|
||||||
|
.contact-page textarea {
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send Message button */
|
||||||
|
.contact-page .bg-primary.rounded-\[12px\] {
|
||||||
|
border-radius: 12px !important;
|
||||||
|
background-color: rgb(38, 60, 111) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-page .bg-primary.rounded-\[12px\]:hover {
|
||||||
|
background-color: rgba(38, 60, 111, 0.9) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon color fix */
|
||||||
|
.contact-page .text-primary i,
|
||||||
|
.contact-page i.text-primary,
|
||||||
|
.contact-page .text-primary svg,
|
||||||
|
.contact-page svg.text-primary {
|
||||||
|
color: rgb(38, 60, 111) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon box bg-blue-50 */
|
||||||
|
.contact-page .bg-blue-50 {
|
||||||
|
background-color: rgb(239, 246, 255) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* blue-100 border */
|
||||||
|
.contact-page .border-blue-100 {
|
||||||
|
border-color: rgb(219, 234, 254) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* info box bg-blue-50 text-primary */
|
||||||
|
.contact-page .bg-blue-50.rounded-\[12px\] {
|
||||||
|
background-color: rgb(239, 246, 255) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon box hover — đổi icon sang trắng khi hover card */
|
||||||
|
.contact-page .group:hover .group-hover\:text-white i,
|
||||||
|
.contact-page .group:hover .group-hover\:text-white svg {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form inputs border-radius và placeholder */
|
||||||
|
.contact-page input,
|
||||||
|
.contact-page select,
|
||||||
|
.contact-page textarea {
|
||||||
|
border-radius: 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-page input::placeholder,
|
||||||
|
.contact-page textarea::placeholder {
|
||||||
|
color: #9ca3af !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* contact-form-title size */
|
||||||
|
.contact-page .contact-form-title {
|
||||||
|
font-size: 2rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consent checkbox alignment */
|
||||||
|
.contact-page .custom-checkbox {
|
||||||
|
margin-top: 2px !important;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
14
app/contactus/page.tsx
Normal file
14
app/contactus/page.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import "./contact.css";
|
||||||
|
import ContactHero from "../components/contactus/ContactHero";
|
||||||
|
import DepartmentDirectory from "../components/contactus/DepartmentDirectory";
|
||||||
|
import ContactSplit from "../components/contactus/ContactSplit";
|
||||||
|
|
||||||
|
export default function ContactUsPage() {
|
||||||
|
return (
|
||||||
|
<main className="contact-page min-h-screen bg-gray-50 pb-20">
|
||||||
|
<ContactHero />
|
||||||
|
<DepartmentDirectory />
|
||||||
|
<ContactSplit />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user