Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 00f477b7a9 | |||
| 83ae5b9524 | |||
| 2bd54da73f | |||
| e82b3f1d81 | |||
| 7ccbec2976 | |||
| b5e7520f7a | |||
| 7f2d5e1957 |
44
src/app/hooks/usePortfolioData.ts
Normal file
44
src/app/hooks/usePortfolioData.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { PortfolioData } from '@/app/types/portfolio';
|
||||
import { fetchGithubJsonFile } from '@/app/lib/github';
|
||||
|
||||
interface UsePortfolioDataResult {
|
||||
portfolio: PortfolioData | null;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
refetch: () => void;
|
||||
}
|
||||
|
||||
const PORTFOLIO_DATA_PATH = 'portfolio.json'; // Assumed filename for structured portfolio data within the repository
|
||||
|
||||
export function usePortfolioData(): UsePortfolioDataResult {
|
||||
const [portfolio, setPortfolio] = useState<PortfolioData | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await fetchGithubJsonFile<PortfolioData>(PORTFOLIO_DATA_PATH);
|
||||
if (data) {
|
||||
setPortfolio(data);
|
||||
} else {
|
||||
setError('Could not fetch portfolio data. Check repository path or file content.');
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Failed to load portfolio data.');
|
||||
console.error('Error in usePortfolioData:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
return { portfolio, loading, error, refetch: fetchData };
|
||||
}
|
||||
25
src/app/lib/github.ts
Normal file
25
src/app/lib/github.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
const GITHUB_REPO_OWNER = 'MamunFarhat';
|
||||
const GITHUB_REPO_NAME = 'aboutmamun';
|
||||
const GITHUB_API_BASE_URL = `https://api.github.com/repos/${GITHUB_REPO_OWNER}/${GITHUB_REPO_NAME}`;
|
||||
|
||||
export async function fetchGithubJsonFile<T>(path: string): Promise<T | null> {
|
||||
try {
|
||||
const response = await fetch(`${GITHUB_API_BASE_URL}/contents/${path}`, {
|
||||
headers: {
|
||||
'Accept': 'application/vnd.github.v3.raw' // Request raw content
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const textContent = await response.text();
|
||||
return JSON.parse(textContent) as T;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error fetching GitHub JSON file from ${path}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
163
src/app/page.tsx
163
src/app/page.tsx
@@ -60,21 +60,11 @@ export default function LandscapingPage() {
|
||||
textPosition="top"
|
||||
testimonials={[
|
||||
{
|
||||
name: "Sarah M.",
|
||||
handle: "Homeowner",
|
||||
testimonial: "GreenScape completely transformed our backyard. The team was professional, creative, and delivered beyond our expectations.",
|
||||
rating: 5,
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/web-agency-2/team-2.jpg",
|
||||
imageAlt: "Sarah M.",
|
||||
},
|
||||
name: "Sarah M.", handle: "Homeowner", testimonial: "GreenScape completely transformed our backyard. The team was professional, creative, and delivered beyond our expectations.", rating: 5,
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/web-agency-2/team-2.jpg", imageAlt: "Sarah M."},
|
||||
{
|
||||
name: "David K.",
|
||||
handle: "Property Manager",
|
||||
testimonial: "We've used GreenScape for all our commercial properties. Their maintenance plans keep everything looking pristine year-round.",
|
||||
rating: 5,
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/web-agency-2/team-1.jpg",
|
||||
imageAlt: "David K.",
|
||||
},
|
||||
name: "David K.", handle: "Property Manager", testimonial: "We've used GreenScape for all our commercial properties. Their maintenance plans keep everything looking pristine year-round.", rating: 5,
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/web-agency-2/team-1.jpg", imageAlt: "David K."},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -106,37 +96,13 @@ export default function LandscapingPage() {
|
||||
imageContainerClassName="!rotate-0 !aspect-square"
|
||||
features={[
|
||||
{
|
||||
tag: "Design",
|
||||
title: "Landscape Design",
|
||||
subtitle: "Custom Plans",
|
||||
description: "We create tailored landscape designs that complement your property's architecture and your personal style.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-2.jpg",
|
||||
imageAlt: "Landscape design",
|
||||
},
|
||||
tag: "Design", title: "Landscape Design", subtitle: "Custom Plans", description: "We create tailored landscape designs that complement your property's architecture and your personal style.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-2.jpg", imageAlt: "Landscape design"},
|
||||
{
|
||||
tag: "Installation",
|
||||
title: "Hardscape & Softscape",
|
||||
subtitle: "Full Installation",
|
||||
description: "From patios and walkways to gardens and trees, we handle the complete installation process.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-3.jpg",
|
||||
imageAlt: "Hardscape installation",
|
||||
},
|
||||
tag: "Installation", title: "Hardscape & Softscape", subtitle: "Full Installation", description: "From patios and walkways to gardens and trees, we handle the complete installation process.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-3.jpg", imageAlt: "Hardscape installation"},
|
||||
{
|
||||
tag: "Maintenance",
|
||||
title: "Lawn & Garden Care",
|
||||
subtitle: "Ongoing Service",
|
||||
description: "Keep your property looking pristine year-round with our professional maintenance plans.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-4.jpg",
|
||||
imageAlt: "Lawn maintenance",
|
||||
},
|
||||
tag: "Maintenance", title: "Lawn & Garden Care", subtitle: "Ongoing Service", description: "Keep your property looking pristine year-round with our professional maintenance plans.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-4.jpg?_wi=1", imageAlt: "Lawn maintenance"},
|
||||
{
|
||||
tag: "Irrigation",
|
||||
title: "Smart Irrigation",
|
||||
subtitle: "Water Management",
|
||||
description: "Efficient irrigation systems that keep your landscape healthy while conserving water.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-5.jpg",
|
||||
imageAlt: "Irrigation system",
|
||||
},
|
||||
tag: "Irrigation", title: "Smart Irrigation", subtitle: "Water Management", description: "Efficient irrigation systems that keep your landscape healthy while conserving water.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-5.jpg", imageAlt: "Irrigation system"},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -148,29 +114,14 @@ export default function LandscapingPage() {
|
||||
textboxLayout="default"
|
||||
useInvertedBackground={false}
|
||||
gridVariant="uniform-all-items-equal"
|
||||
animationType="slide-up"
|
||||
animationType="depth-3d"
|
||||
members={[
|
||||
{
|
||||
id: "1",
|
||||
name: "Expert Craftsmanship",
|
||||
role: "Decades of combined experience in landscape design and installation.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-6.jpg",
|
||||
imageAlt: "Expert craftsmanship",
|
||||
},
|
||||
id: "1", name: "Expert Craftsmanship", role: "Decades of combined experience in landscape design and installation.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-6.jpg", imageAlt: "Expert craftsmanship"},
|
||||
{
|
||||
id: "2",
|
||||
name: "Eco-Friendly Approach",
|
||||
role: "Sustainable practices and native plant selections that thrive naturally.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-7.jpg",
|
||||
imageAlt: "Eco-friendly landscaping",
|
||||
},
|
||||
id: "2", name: "Eco-Friendly Approach", role: "Sustainable practices and native plant selections that thrive naturally.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-7.jpg", imageAlt: "Eco-friendly landscaping"},
|
||||
{
|
||||
id: "3",
|
||||
name: "Full-Service Care",
|
||||
role: "From initial design to ongoing maintenance, we handle everything.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-8.jpg",
|
||||
imageAlt: "Full-service care",
|
||||
},
|
||||
id: "3", name: "Full-Service Care", role: "From initial design to ongoing maintenance, we handle everything.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-8.jpg", imageAlt: "Full-service care"},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -186,26 +137,11 @@ export default function LandscapingPage() {
|
||||
animationType="slide-up"
|
||||
members={[
|
||||
{
|
||||
id: "1",
|
||||
name: "James Carter",
|
||||
role: "Lead Designer",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-11.jpg",
|
||||
imageAlt: "James Carter",
|
||||
},
|
||||
id: "1", name: "James Carter", role: "Lead Designer", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-11.jpg?_wi=1", imageAlt: "James Carter"},
|
||||
{
|
||||
id: "2",
|
||||
name: "Maria Silva",
|
||||
role: "Horticulturist",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-10.jpg",
|
||||
imageAlt: "Maria Silva",
|
||||
},
|
||||
id: "2", name: "Maria Silva", role: "Horticulturist", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-10.jpg?_wi=1", imageAlt: "Maria Silva"},
|
||||
{
|
||||
id: "3",
|
||||
name: "Ryan Mitchell",
|
||||
role: "Project Manager",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-9.jpg",
|
||||
imageAlt: "Ryan Mitchell",
|
||||
},
|
||||
id: "3", name: "Ryan Mitchell", role: "Project Manager", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-9.jpg?_wi=1", imageAlt: "Ryan Mitchell"},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -221,29 +157,13 @@ export default function LandscapingPage() {
|
||||
useInvertedBackground={false}
|
||||
testimonials={[
|
||||
{
|
||||
id: "1",
|
||||
name: "Sarah M.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-10.jpg",
|
||||
imageAlt: "Sarah M.",
|
||||
},
|
||||
id: "1", name: "Sarah M.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-10.jpg?_wi=2", imageAlt: "Sarah M."},
|
||||
{
|
||||
id: "2",
|
||||
name: "David K.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-11.jpg",
|
||||
imageAlt: "David K.",
|
||||
},
|
||||
id: "2", name: "David K.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-11.jpg?_wi=2", imageAlt: "David K."},
|
||||
{
|
||||
id: "3",
|
||||
name: "Emily R.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-4.jpg",
|
||||
imageAlt: "Emily R.",
|
||||
},
|
||||
id: "3", name: "Emily R.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-4.jpg?_wi=2", imageAlt: "Emily R."},
|
||||
{
|
||||
id: "4",
|
||||
name: "Ryan M.",
|
||||
imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-9.jpg",
|
||||
imageAlt: "Ryan M.",
|
||||
},
|
||||
id: "4", name: "Ryan M.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/templates/landscaping/img-9.jpg?_wi=2", imageAlt: "Ryan M."},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -258,35 +178,17 @@ export default function LandscapingPage() {
|
||||
faqsAnimation="slide-up"
|
||||
faqs={[
|
||||
{
|
||||
id: "1",
|
||||
title: "How long does a typical landscaping project take?",
|
||||
content: "Most residential projects take 1-3 weeks depending on scope. We'll provide a detailed timeline during your consultation so you know exactly what to expect.",
|
||||
},
|
||||
id: "1", title: "How long does a typical landscaping project take?", content: "Most residential projects take 1-3 weeks depending on scope. We'll provide a detailed timeline during your consultation so you know exactly what to expect."},
|
||||
{
|
||||
id: "2",
|
||||
title: "Do you offer free consultations?",
|
||||
content: "Yes! We offer complimentary on-site consultations where we assess your property, discuss your vision, and provide a detailed estimate — no obligation.",
|
||||
},
|
||||
id: "2", title: "Do you offer free consultations?", content: "Yes! We offer complimentary on-site consultations where we assess your property, discuss your vision, and provide a detailed estimate — no obligation."},
|
||||
{
|
||||
id: "3",
|
||||
title: "What areas do you serve?",
|
||||
content: "We serve the greater metropolitan area and surrounding suburbs within a 50-mile radius. Contact us to confirm service availability in your location.",
|
||||
},
|
||||
id: "3", title: "What areas do you serve?", content: "We serve the greater metropolitan area and surrounding suburbs within a 50-mile radius. Contact us to confirm service availability in your location."},
|
||||
{
|
||||
id: "4",
|
||||
title: "Do you provide ongoing maintenance?",
|
||||
content: "Absolutely. We offer weekly, bi-weekly, and monthly maintenance plans that include mowing, trimming, fertilization, and seasonal cleanups.",
|
||||
},
|
||||
id: "4", title: "Do you provide ongoing maintenance?", content: "Absolutely. We offer weekly, bi-weekly, and monthly maintenance plans that include mowing, trimming, fertilization, and seasonal cleanups."},
|
||||
{
|
||||
id: "5",
|
||||
title: "Are your practices eco-friendly?",
|
||||
content: "Yes, sustainability is core to our approach. We use native plants, organic fertilizers, smart irrigation, and environmentally responsible methods whenever possible.",
|
||||
},
|
||||
id: "5", title: "Are your practices eco-friendly?", content: "Yes, sustainability is core to our approach. We use native plants, organic fertilizers, smart irrigation, and environmentally responsible methods whenever possible."},
|
||||
{
|
||||
id: "6",
|
||||
title: "Do you handle permits and HOA approvals?",
|
||||
content: "We handle all necessary permits and can work directly with your HOA to ensure your project meets community guidelines and gets approved smoothly.",
|
||||
},
|
||||
id: "6", title: "Do you handle permits and HOA approvals?", content: "We handle all necessary permits and can work directly with your HOA to ensure your project meets community guidelines and gets approved smoothly."},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -319,9 +221,7 @@ export default function LandscapingPage() {
|
||||
{ name: "phone", type: "tel", placeholder: "Phone Number" },
|
||||
]}
|
||||
multiSelect={{
|
||||
name: "service",
|
||||
label: "Select a Service",
|
||||
options: ["Landscape Design", "Hardscape & Softscape", "Lawn & Garden Care", "Smart Irrigation"],
|
||||
name: "service", label: "Select a Service", options: ["Landscape Design", "Hardscape & Softscape", "Lawn & Garden Care", "Smart Irrigation"],
|
||||
}}
|
||||
textarea={{ name: "message", placeholder: "Tell us about your project...", rows: 4, required: true }}
|
||||
/>
|
||||
@@ -331,8 +231,7 @@ export default function LandscapingPage() {
|
||||
<FooterSimple
|
||||
columns={[
|
||||
{
|
||||
title: "Services",
|
||||
items: [
|
||||
title: "Services", items: [
|
||||
{ label: "Landscape Design", href: "#services" },
|
||||
{ label: "Hardscape & Softscape", href: "#services" },
|
||||
{ label: "Lawn & Garden Care", href: "#services" },
|
||||
@@ -340,8 +239,7 @@ export default function LandscapingPage() {
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Company",
|
||||
items: [
|
||||
title: "Company", items: [
|
||||
{ label: "About", href: "#about" },
|
||||
{ label: "Team", href: "#team" },
|
||||
{ label: "Testimonials", href: "#testimonials" },
|
||||
@@ -349,8 +247,7 @@ export default function LandscapingPage() {
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Contact",
|
||||
items: [
|
||||
title: "Contact", items: [
|
||||
{ label: "(555) 123-4567", href: "tel:5551234567" },
|
||||
{ label: "hello@greenscape.com", href: "mailto:hello@greenscape.com" },
|
||||
{ label: "Los Angeles, CA" },
|
||||
@@ -364,4 +261,4 @@ export default function LandscapingPage() {
|
||||
</ReactLenis>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
33
src/app/types/portfolio.ts
Normal file
33
src/app/types/portfolio.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
export interface Project {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
technologies: string[];
|
||||
githubUrl?: string;
|
||||
demoUrl?: string;
|
||||
imageUrl?: string;
|
||||
}
|
||||
|
||||
export interface Skill {
|
||||
name: string;
|
||||
category: string; // e.g., 'Frontend', 'Backend', 'DevOps'
|
||||
level?: 'Beginner' | 'Intermediate' | 'Advanced' | 'Expert';
|
||||
}
|
||||
|
||||
export interface Experience {
|
||||
id: string;
|
||||
title: string;
|
||||
company: string;
|
||||
location: string;
|
||||
startDate: string; // YYYY-MM-DD
|
||||
endDate?: string; // YYYY-MM-DD or 'Present'
|
||||
description: string[];
|
||||
}
|
||||
|
||||
export interface PortfolioData {
|
||||
name: string;
|
||||
bio: string;
|
||||
projects: Project[];
|
||||
skills: Skill[];
|
||||
experience: Experience[];
|
||||
}
|
||||
Reference in New Issue
Block a user