diff --git a/app/blog/blog-page.css b/app/blog/blog-page.css new file mode 100644 index 0000000..5cb4b50 --- /dev/null +++ b/app/blog/blog-page.css @@ -0,0 +1,176 @@ +/* ============================================ + Blog Page — Scoped Styles + Scope: .blog-page + ============================================ */ + +/* Reset heading override từ main.css */ +.blog-page h1, +.blog-page h2, +.blog-page h3, +.blog-page h4 { + font-size: unset; + font-weight: unset; + line-height: unset; + margin: 0; + padding: 0; +} + +/* Typography classes thay thế h1/h2/h3 */ +.blog-page .blog-heading { + font-size: clamp(1.75rem, 4vw, 3rem); + font-weight: 700; + line-height: 1.15; +} + +.blog-page .blog-card-title { + font-size: 1.1rem; + font-weight: 700; + line-height: 1.3; +} + +.blog-page .blog-widget-title { + font-size: 1.1rem; + font-weight: 700; + line-height: 1.3; +} + +/* ---------- Color tokens ---------- */ + +.blog-page .bg-brand-blue { background-color: rgb(38, 60, 111); } +.blog-page .text-brand-blue { color: rgb(38, 60, 111); } +.blog-page .border-brand-blue { border-color: rgb(38, 60, 111); } + +.blog-page .bg-brand-light { background-color: #f8fbff; } +.blog-page .text-brand-light { color: #f8fbff; } + +.blog-page .bg-brand-hover { background-color: #2d3a8c; } +.blog-page .hover\:bg-brand-hover:hover { background-color: #2d3a8c; } + +.blog-page .text-ui-text { color: #111827; } +.blog-page .text-ui-muted { color: #6b7280; } +.blog-page .bg-ui-bg { background-color: #f9fafb; } +.blog-page .border-ui-border { border-color: #e5e7eb; } + +/* hover:text-brand-blue */ +.blog-page .hover\:text-brand-blue:hover { color: #1b254b; } +.blog-page .hover\:border-brand-blue:hover { border-color: #1b254b; } + +/* group-hover */ +.blog-page .group:hover .group-hover\:text-brand-blue { color: #1b254b; } +.blog-page .group:hover .group-hover\:border-brand-blue { border-color: #1b254b; } +.blog-page .group:hover .group-hover\:gap-2 { gap: 0.5rem; } +.blog-page .group:hover .group-hover\:scale-105 { transform: scale(1.05); } + +/* shadow tokens */ +.blog-page .shadow-soft { + box-shadow: 0 1px 3px rgb(0 0 0 / 0.06), 0 1px 2px rgb(0 0 0 / 0.04); +} +.blog-page .shadow-hover { + box-shadow: 0 4px 12px rgb(0 0 0 / 0.1); +} +.blog-page .hover\:shadow-hover:hover { + box-shadow: 0 4px 12px rgb(0 0 0 / 0.1); +} + +/* border-brand-blue/20, border-brand-blue/50 */ +.blog-page .border-brand-blue\/20 { border-color: rgb(27 37 75 / 0.2); } +.blog-page .border-brand-blue\/50 { border-color: rgb(27 37 75 / 0.5); } +.blog-page .hover\:border-brand-blue\/50:hover { border-color: rgb(27 37 75 / 0.5); } + +/* text-brand-blue/40 */ +.blog-page .text-brand-blue\/40 { color: rgb(27 37 75 / 0.4); } + +/* text-brand-light/80, /60 */ +.blog-page .text-brand-light\/80 { color: rgb(248 251 255 / 0.8); } +.blog-page .text-brand-light\/60 { color: rgb(248 251 255 / 0.6); } + +/* bg-white/10, /90 */ +.blog-page .bg-white\/10 { background-color: rgb(255 255 255 / 0.1); } +.blog-page .bg-white\/90 { background-color: rgb(255 255 255 / 0.9); } + +/* border-white/20 */ +.blog-page .border-white\/20 { border-color: rgb(255 255 255 / 0.2); } + +/* placeholder */ +.blog-page .placeholder-white\/50::placeholder { color: rgb(255 255 255 / 0.5); } + +/* Category filter buttons */ +.blog-page #category-filters button { + padding-left: 1.25rem !important; + padding-right: 1.25rem !important; + padding-top: 0.4rem !important; + padding-bottom: 0.4rem !important; + border-radius: 9999px !important; + font-size: 0.8rem !important; +} + +/* Category filter hover — viền sáng lên */ +.blog-page #category-filters button:not(:first-child):hover { + border-color: #1b254b !important; + color: #1b254b !important; +} + +/* Newsletter input placeholder */ +.blog-page .newsletter-input::placeholder { + color: rgba(255, 255, 255, 0.5); +} + +/* Newsletter widget */ +.blog-page .folder-tab { + background-color: #263c6f !important; + clip-path: polygon(0 0, calc(100% - 40px) 0, 100% 40px, 100% 100%, 0 100%); + border-radius: 12px !important; +} + +.blog-page .folder-tab input { + border-radius: 8px !important; + padding: 0.35rem 0.75rem !important; + font-size: 0.875rem !important; + background-color: rgba(255,255,255,0.12) !important; + border: 1px solid rgba(255,255,255,0.25) !important; + color: white !important; +} + +.blog-page .folder-tab input::placeholder { + color: rgba(255,255,255,0.5) !important; +} + +.blog-page .folder-tab button[type="submit"] { + border-radius: 8px !important; + padding: 0.35rem 0.75rem !important; + font-size: 0.875rem !important; + font-weight: 700 !important; + background-color: white !important; + color: #1b254b !important; +} + +/* Pagination buttons */ +.blog-page .border-ui-border[class*="w-10"] { + border-radius: 8px !important; +} + +.blog-page .border-ui-border[class*="w-10"]:hover { + border-color: rgb(38, 60, 111) !important; + color: rgb(38, 60, 111) !important; +} + +.blog-page .bg-brand-blue[class*="w-10"] { + border-radius: 8px !important; + background-color: rgb(38, 60, 111) !important; +} + +/* Pagination */ +.blog-page .pg-btn { + border-radius: 8px !important; + transition: border-color 0.2s, color 0.2s; +} + +.blog-page .pg-btn:hover { + border-color: rgb(38, 60, 111) !important; + color: rgb(38, 60, 111) !important; +} + +.blog-page .pg-active { + background-color: rgb(38, 60, 111) !important; + border: none !important; +} diff --git a/app/blog/page.tsx b/app/blog/page.tsx index e69de29..ad577fc 100644 --- a/app/blog/page.tsx +++ b/app/blog/page.tsx @@ -0,0 +1,26 @@ +import "./blog-page.css"; +import FeaturedHero from "../components/blog/FeaturedHero"; +import CategoryFilters from "../components/blog/CategoryFilters"; +import NewsGrid from "../components/blog/NewsGrid"; +import BlogSidebar from "../components/blog/BlogSidebar"; + +export default function BlogPage() { + return ( +
+ + +
+
+ {/* Left: filters + news grid */} +
+ + +
+ + {/* Right: sidebar */} + +
+
+
+ ); +} diff --git a/app/components/blog/BlogSidebar.tsx b/app/components/blog/BlogSidebar.tsx new file mode 100644 index 0000000..3adbf25 --- /dev/null +++ b/app/components/blog/BlogSidebar.tsx @@ -0,0 +1,13 @@ +import NewsletterWidget from "./NewsletterWidget"; +import ResearcherSpotlight from "./ResearcherSpotlight"; +import UpcomingEvents from "./UpcomingEvents"; + +export default function BlogSidebar() { + return ( + + ); +} diff --git a/app/components/blog/CategoryFilters.tsx b/app/components/blog/CategoryFilters.tsx new file mode 100644 index 0000000..fb413d0 --- /dev/null +++ b/app/components/blog/CategoryFilters.tsx @@ -0,0 +1,21 @@ +const categories = ["All News", "Campus", "Research", "Partnerships", "Events"]; + +export default function CategoryFilters() { + return ( +
+ {categories.map((cat, i) => ( + + ))} +
+ ); +} diff --git a/app/components/blog/FeaturedHero.tsx b/app/components/blog/FeaturedHero.tsx new file mode 100644 index 0000000..a1525bc --- /dev/null +++ b/app/components/blog/FeaturedHero.tsx @@ -0,0 +1,44 @@ +export default function FeaturedHero() { + return ( + + ); +} diff --git a/app/components/blog/NewsCard.tsx b/app/components/blog/NewsCard.tsx new file mode 100644 index 0000000..806a3a0 --- /dev/null +++ b/app/components/blog/NewsCard.tsx @@ -0,0 +1,48 @@ +type NewsCardProps = { + category: string; + date: string; + title: string; + excerpt: string; + image?: string; + icon?: string; +}; + +export default function NewsCard({ category, date, title, excerpt, image, icon }: NewsCardProps) { + return ( +
+ {/* Thumbnail */} +
+ {image ? ( + {title} + ) : ( +
+ +
+ )} +
+ + {category} + +
+
+ + {/* Content */} +
+
+ {date} +
+
+ {title} +
+

{excerpt}

+ + Read more + +
+
+ ); +} diff --git a/app/components/blog/NewsGrid.tsx b/app/components/blog/NewsGrid.tsx new file mode 100644 index 0000000..1d88770 --- /dev/null +++ b/app/components/blog/NewsGrid.tsx @@ -0,0 +1,59 @@ +import NewsCard from "./NewsCard"; + +const news = [ + { + category: "Campus", + date: "Oct 12, 2024", + title: "New Liberal Arts Library Wing Opens to Students", + excerpt: "The state-of-the-art facility provides expanded collaborative spaces and access to over 50,000 new digital and print resources for our growing student body.", + image: "https://storage.googleapis.com/uxpilot-auth.appspot.com/8eafd095d9-314bdad36b2119266084.png", + }, + { + category: "Partnerships", + date: "Oct 10, 2024", + title: "ULP Announces Strategic Alliance with TechGlobal Institute", + excerpt: "A new partnership aimed at bridging the gap between liberal arts education and emerging technological paradigms in the 21st century.", + icon: "fas fa-handshake", + }, + { + category: "Events", + date: "Oct 05, 2024", + title: "Annual Global Ethics Symposium Draws Record Attendance", + excerpt: "Scholars from over 40 countries gathered at ULP this weekend to discuss the evolving landscape of international human rights and digital privacy.", + image: "https://storage.googleapis.com/uxpilot-auth.appspot.com/fc832714d8-ee7527b4d94c300aae71.png", + }, + { + category: "Research", + date: "Sep 28, 2024", + title: "Department of Sociology Publishes Landmark Study on Urban Migration", + excerpt: "A comprehensive 5-year study reveals shifting demographic patterns in post-industrial European cities, highlighting new socio-economic challenges.", + icon: "fas fa-flask", + }, +]; + +export default function NewsGrid() { + return ( +
+
+ {news.map((item) => ( + + ))} +
+ + {/* Pagination */} +
+ + + + + ... + + +
+
+ ); +} diff --git a/app/components/blog/NewsletterWidget.tsx b/app/components/blog/NewsletterWidget.tsx new file mode 100644 index 0000000..ab9db59 --- /dev/null +++ b/app/components/blog/NewsletterWidget.tsx @@ -0,0 +1,37 @@ +export default function NewsletterWidget() { + return ( +
+
+
Stay Informed
+

+ Subscribe to our weekly newsletter for the latest research updates, campus news, and upcoming events. +

+
+
+ +
+ +
+

+ By subscribing, you agree to our{" "} + Privacy Policy. +

+
+ + {/* Decorative background element */} +
+ +
+
+ ); +} diff --git a/app/components/blog/ResearcherSpotlight.tsx b/app/components/blog/ResearcherSpotlight.tsx new file mode 100644 index 0000000..6be6691 --- /dev/null +++ b/app/components/blog/ResearcherSpotlight.tsx @@ -0,0 +1,47 @@ +const researchers = [ + { + name: "Dr. Sarah Jenkins", + field: "Cognitive Linguistics", + bio: "Exploring the intersection of language processing and modern ethical frameworks in digital communication.", + avatar: "https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-5.jpg", + }, + { + name: "Prof. Marcus Chen", + field: "Economic History", + bio: "Recent recipient of the European Heritage Grant for his work on interwar economic policies.", + avatar: "https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-4.jpg", + }, + { + name: "Dr. Elena Rostova", + field: "Political Science", + bio: "Leading the new comparative study on post-war democratic institutions across Western Europe.", + avatar: "https://storage.googleapis.com/uxpilot-auth.appspot.com/avatars/avatar-6.jpg", + }, +]; + +export default function ResearcherSpotlight() { + return ( +
+
+
Researcher Spotlight
+ View All +
+
+ {researchers.map((r) => ( +
+ {r.name} +
+
{r.name}
+

{r.field}

+

{r.bio}

+
+
+ ))} +
+
+ ); +} diff --git a/app/components/blog/UpcomingEvents.tsx b/app/components/blog/UpcomingEvents.tsx new file mode 100644 index 0000000..30da6f0 --- /dev/null +++ b/app/components/blog/UpcomingEvents.tsx @@ -0,0 +1,40 @@ +const events = [ + { + month: "Nov", + day: "12", + title: "Open Campus Day", + time: "09:00 AM - 04:00 PM", + }, + { + month: "Nov", + day: "18", + title: "Guest Lecture: Future of AI in Arts", + time: "06:00 PM - Main Hall", + }, +]; + +export default function UpcomingEvents() { + return ( +
+
+ Upcoming Events +
+ +
+ ); +}