Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MG-8 - Refactor the Landing Page Components #17

Merged
merged 12 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"predeploy": "npm run build",
"deploy": "gh-pages -d out"
},
"homepage": "https://absmach.github.io/mg-website",
"homepage": "https://Musilah.github.io/mg-website",
Musilah marked this conversation as resolved.
Show resolved Hide resolved
"dependencies": {
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-separator": "^1.1.1",
Expand Down
114 changes: 114 additions & 0 deletions public/student-in-the-classroom.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,22 @@ body {
body {
@apply bg-background text-foreground;
}
html {
font-size: 16px;
}
@media (max-width: 768px) {
html {
font-size: 14px;
}
}

@media (max-width: 480px) {
html {
font-size: 12px;
}
}

body {
line-height: 1.5;
}
}
97 changes: 15 additions & 82 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { BenefitsSection } from '@/components/benefits-card';
import { ComingSoonBanner } from '@/components/coming-soonbanner';
import { FAQCard } from '@/components/faq-card';
import { ProductFeatureCard } from '@/components/features-card';
import { Hero } from '@/components/hero';
import { PoweredBy } from '@/components/powered-by';
import { UseCasesTabs } from '@/components/usecase-tab';
import { BenefitsSection } from "@/components/benefits-card";
import { ComingSoonBanner } from "@/components/coming-soonbanner";
import { FAQSection } from "@/components/faq-card";
import {
benefitsData,
faqData,
featuresData,
heroData,
useCasesData,
} from '@/lib/constants';
FeaturesSection,
ProductFeatureCard,
} from "@/components/features-card";
import { NextFeaturesSection } from "@/components/future-features-card";
import { Hero } from "@/components/hero";
import { PoweredBy } from "@/components/powered-by";
import { heroData } from "@/lib/constants";
import { UseCasesSection } from "@/components/usecase-tab";

export default function Home() {
return (
Expand All @@ -32,64 +30,13 @@ export default function Home() {
<PoweredBy />

{/* Features Section */}
<section id="features" className="py-20 bg-blue-200">
<div className="container mx-auto max-w-6xl px-6">
<h2 className="text-3xl font-bold mb-4 text-center text-blue-950">
Explore Our Features
</h2>
<p className="text-lg text-gray-700 mb-12 text-center">
Discover tools that make your development journey seamless and
scalable.
</p>

<div className="space-y-12">
{featuresData.map((feature, index) => (
<div key={feature.title} className=" last:border-none pb-4">
<ProductFeatureCard
title={feature.title}
description={feature.description}
reverse={index % 2 !== 0}
imageUrl={feature.imageUrl}
/>
</div>
))}
</div>
</div>
</section>
<FeaturesSection />

{/* Future Features Section */}
{/* <section id="next-features" className="py-20 bg-blue-200">
<div className="container mx-auto px-6 text-center">
<h2 className="text-3xl font-bold mb-4">Thats not all!</h2>
<p className="text-lg text-gray-700 mb-12">
We have a range of exciting new updates still on the drawing board
to look forward to!
</p>
<div className="container mx-auto px-6 grid grid-cols-1 md:grid-cols-3 gap-8">
{futureFeaturesData.map((futureFeature, index) => (
<ProductFutureFeatureCard
// biome-ignore lint/suspicious/noArrayIndexKey: This is needed for the constants
key={index}
title={futureFeature.title}
description={futureFeature.description}
imageUrl={futureFeature.imageUrl}
/>
))}
</div>
</div>
</section> */}
<NextFeaturesSection />

{/* Use Cases Tabs */}
<section id="use-cases" className="bg-gray-100 py-20">
<div className="container mx-auto px-6">
<h2 className="text-3xl font-bold text-center mb-8">Use Cases</h2>
<p className="text-lg text-gray-700 text-center mb-8">
Here are some real world solutions that Magistrala has aided in
fruition
</p>
<UseCasesTabs useCases={useCasesData} />
</div>
</section>
<UseCasesSection />

{/* Pricing Section*/}

Expand All @@ -99,21 +46,7 @@ export default function Home() {
<ComingSoonBanner />

{/* FAQ Section */}
<section id="faq" className=" bg-gray-100 py-20 ">
<div className="container mx-auto px-6">
<h2 className="text-3xl font-bold text-center mb-12">FAQs</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{faqData.map((faqCategory, index) => (
<FAQCard
// biome-ignore lint/suspicious/noArrayIndexKey:
key={index}
title={faqCategory.title}
faqs={faqCategory.faqs}
/>
))}
</div>
</div>
</section>
<FAQSection />
</div>
);
}
56 changes: 35 additions & 21 deletions src/components/faq-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,43 @@ import {
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion';
} from "@/components/ui/accordion";
import { faqSectionData } from "@/lib/constants";
import { getImageUrl } from "@/lib/getImageUrl";

interface FAQCardProps {
title: string;
faqs: {
question: string;
answer: string;
}[];
}
export function FAQSection() {
const { sectionId, title, faqs } = faqSectionData;
const faqImage = "student-in-the-classroom.svg";

export function FAQCard({ title, faqs }: FAQCardProps) {
return (
<div className="overflow-hidden bg-amber-50 shadow-md rounded-lg p-6">
<h3 className="text-2xl font-bold tracking-tight mb-4">{title}</h3>
<Accordion type="single" collapsible>
{faqs.map((faq, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey:
<AccordionItem key={index} value={`faq-${index}`}>
<AccordionTrigger>{faq.question}</AccordionTrigger>
<AccordionContent>{faq.answer}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
<section id={sectionId} className="bg-gray-100 py-20">
<div className="container mx-auto px-6">
<h2 className="text-3xl font-bold text-center mb-12">{title}</h2>
{/* FAQ card */}
<div className="flex flex-col md:flex-row items-center bg-white rounded-lg shadow-lg overflow-hidden">
<div className="w-full md:w-1/2 h-64 md:h-auto relative">
<img
src={getImageUrl(faqImage)}
alt="FAQs Illustration"
className="object-cover w-full h-full"
/>
</div>
<div className="w-full md:w-1/2 p-6 space-y-6">
<Accordion type="single" collapsible>
{faqSectionData.faqs.map((faq, index) => (
<AccordionItem key={faq.question} value={`faq-${index}`}>
<AccordionTrigger className="font-semibold text-grey-600 text-md">
{faq.question}
</AccordionTrigger>
<AccordionContent className="text-gray-700">
{faq.answer}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</div>
</div>
</section>
);
}
35 changes: 32 additions & 3 deletions src/components/features-card.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getImageUrl } from '@/lib/getImageUrl';
import Image from 'next/image';
import { getImageUrl } from "@/lib/getImageUrl";
import Image from "next/image";
import { featuresSectionData } from "@/lib/constants";

interface ProductFeatureCardProps {
title: string;
Expand All @@ -17,7 +18,7 @@ export function ProductFeatureCard({
return (
<div
className={`flex flex-col md:flex-row items-center justify-between gap-8 py-6 ${
reverse ? 'md:flex-row-reverse' : ''
reverse ? "md:flex-row-reverse" : ""
}`}
>
<div className="w-full md:w-1/2 space-y-4">
Expand All @@ -36,3 +37,31 @@ export function ProductFeatureCard({
</div>
);
}

export function FeaturesSection() {
const { sectionId, title, subtitle, features } = featuresSectionData;

return (
<section id={sectionId} className="py-20 bg-blue-200">
<div className="container mx-auto max-w-6xl px-6">
<h2 className="text-3xl font-bold mb-4 text-center text-blue-950">
{title}
</h2>
<p className="text-lg text-gray-700 mb-12 text-center">{subtitle}</p>

<div className="space-y-12">
{features.map((feature, index) => (
<div key={feature.title} className="last:border-none pb-4">
<ProductFeatureCard
title={feature.title}
description={feature.description}
reverse={index % 2 !== 0}
imageUrl={feature.imageUrl}
/>
</div>
))}
</div>
</div>
</section>
);
}
23 changes: 23 additions & 0 deletions src/components/footer-bottom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Link from "next/link";
import { footerData } from "@/lib/constants";

export function FooterBottom() {
const { year, rights, policies } = footerData.footerBottom;

return (
<div className="mt-12">
<div className="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
<p className="text-sm text-muted-foreground">
&copy; {year} Abstract Machines. {rights}
</p>
<div className="flex space-x-4 text-sm text-muted-foreground">
{policies.map((policy, index) => (
<Link key={policy.label} href={policy.href} className="hover:text-primary transition-colors">
{policy.label}
</Link>
))}
</div>
</div>
</div>
);
}
15 changes: 15 additions & 0 deletions src/components/footer-company-info.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Image from "next/image";
import { getImageUrl } from "@/lib/getImageUrl";
import { footerData } from "@/lib/constants";

export function FooterCompanyInfo() {
const { logo, name, description } = footerData.companyInfo;

return (
<div className="space-y-4">
<Image src={getImageUrl(logo)} alt={`${name} Logo`} width={200} height={200} />
<h3 className="text-xl font-bold tracking-tight">{name}</h3>
<p className="text-muted-foreground leading-relaxed">{description}</p>
</div>
);
}
21 changes: 21 additions & 0 deletions src/components/footer-newsletter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Button } from "@/components/ui/button";
import { footerData } from "@/lib/constants";

export function FooterNewsletter() {
const { title, subtitle, placeholder, buttonText } = footerData.newsletter;

return (
<div className="space-y-4">
<h4 className="font-semibold">{title}</h4>
<p className="text-sm text-muted-foreground">{subtitle}</p>
<form className="flex items-center gap-2">
<input
type="email"
placeholder={placeholder}
className="flex-grow p-2 rounded-md border border-gray-300 text-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<Button className="bg-blue-800 hover:bg-blue-600">{buttonText}</Button>
</form>
</div>
);
}
21 changes: 21 additions & 0 deletions src/components/footer-quick-links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Link from "next/link";
import { footerData } from "@/lib/constants";

export function FooterQuickLinks() {
return (
<div className="space-y-4">
<h4 className="font-semibold">Quick Links</h4>
<nav className="flex flex-col space-y-2">
{footerData.quickLinks.map((link, index) => (
<Link
key={link.label}
href={link.href}
className="text-muted-foreground hover:text-primary transition-colors"
>
{link.label}
</Link>
))}
</nav>
</div>
);
}
34 changes: 34 additions & 0 deletions src/components/footer-social-links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Github, Linkedin, Mail, Twitter } from "lucide-react";
import { Button } from "@/components/ui/button";
import { footerData } from "@/lib/constants";

const icons = {
Twitter,
Linkedin,
Github,
} as const;

export function FooterSocialLinks() {
return (
<div className="space-y-4">
<h4 className="font-semibold">Connect With Us</h4>
<div className="flex flex-col space-y-2">
{footerData.socialLinks.map((link) => {
const Icon = icons[link.icon as keyof typeof icons];
return (
<a
key={link.platform}
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="flex items-center text-muted-foreground hover:text-primary transition-colors"
>
<Icon className="h-4 w-4 mr-2" />
{link.platform}
</a>
);
})}
</div>
</div>
);
}
Loading