From bbf36b0e67a99c3fef1fafabdd3bfb8def0b7bcd Mon Sep 17 00:00:00 2001 From: "amazon-q-developer[bot]" <208079219+amazon-q-developer[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 11:39:51 +0000 Subject: [PATCH] feat: Initialize travel blog frontend with destinations features Add core travel blog functionality including home page, destination details, navbar and footer components. Set up routing and styling for a responsive travel destination showcase application. --- package.json | 36 +++++++ public/index.html | 21 ++++ src/App.css | 17 ++++ src/App.js | 24 +++++ src/components/Footer.css | 63 ++++++++++++ src/components/Footer.js | 38 +++++++ src/components/Navbar.css | 42 ++++++++ src/components/Navbar.js | 28 +++++ src/data/destinations.js | 40 ++++++++ src/index.css | 27 +++++ src/index.js | 14 +++ src/pages/DestinationDetail.css | 167 ++++++++++++++++++++++++++++++ src/pages/DestinationDetail.js | 90 ++++++++++++++++ src/pages/Home.css | 175 ++++++++++++++++++++++++++++++++ src/pages/Home.js | 52 ++++++++++ 15 files changed, 834 insertions(+) create mode 100644 package.json create mode 100644 public/index.html create mode 100644 src/App.css create mode 100644 src/App.js create mode 100644 src/components/Footer.css create mode 100644 src/components/Footer.js create mode 100644 src/components/Navbar.css create mode 100644 src/components/Navbar.js create mode 100644 src/data/destinations.js create mode 100644 src/index.css create mode 100644 src/index.js create mode 100644 src/pages/DestinationDetail.css create mode 100644 src/pages/DestinationDetail.js create mode 100644 src/pages/Home.css create mode 100644 src/pages/Home.js diff --git a/package.json b/package.json new file mode 100644 index 0000000..9123eb0 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "travel-blog", + "version": "0.1.0", + "private": true, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.16.0", + "react-scripts": "5.0.1", + "web-vitals": "^2.1.4" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..3d4fe61 --- /dev/null +++ b/public/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + Travel Blog - Explore the World + + + + +
+ + \ No newline at end of file diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..19a6934 --- /dev/null +++ b/src/App.css @@ -0,0 +1,17 @@ +.App { + display: flex; + flex-direction: column; + min-height: 100vh; +} + +main { + flex-grow: 1; + padding: 60px 0; +} + +.page-title { + text-align: center; + margin-bottom: 40px; + color: #333; + font-size: 2.5rem; +} \ No newline at end of file diff --git a/src/App.js b/src/App.js new file mode 100644 index 0000000..71e4c7a --- /dev/null +++ b/src/App.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { Routes, Route } from 'react-router-dom'; +import './App.css'; +import Navbar from './components/Navbar'; +import Footer from './components/Footer'; +import Home from './pages/Home'; +import DestinationDetail from './pages/DestinationDetail'; + +function App() { + return ( +
+ +
+ + } /> + } /> + +
+
+ ); +} + +export default App; \ No newline at end of file diff --git a/src/components/Footer.css b/src/components/Footer.css new file mode 100644 index 0000000..ae7c483 --- /dev/null +++ b/src/components/Footer.css @@ -0,0 +1,63 @@ +.footer { + background-color: #f0f2f5; + padding: 60px 0 20px; + margin-top: 40px; +} + +.footer-container { + display: flex; + flex-direction: column; +} + +.footer-content { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin-bottom: 40px; +} + +.footer-section { + flex: 1; + margin-right: 30px; + min-width: 200px; + margin-bottom: 20px; +} + +.footer-section:last-child { + margin-right: 0; +} + +.footer-section h3 { + margin-bottom: 15px; + font-size: 1.2rem; + color: #0066cc; +} + +.footer-section p { + color: #555; +} + +.footer-section ul { + list-style: none; +} + +.footer-section ul li { + margin-bottom: 8px; +} + +.social-links { + display: flex; + flex-direction: column; +} + +.social-links a { + margin-bottom: 8px; +} + +.footer-bottom { + text-align: center; + padding-top: 20px; + border-top: 1px solid #ddd; + color: #777; + font-size: 0.9rem; +} \ No newline at end of file diff --git a/src/components/Footer.js b/src/components/Footer.js new file mode 100644 index 0000000..3e6d81d --- /dev/null +++ b/src/components/Footer.js @@ -0,0 +1,38 @@ +import React from 'react'; +import './Footer.css'; + +function Footer() { + return ( + + ); +} + +export default Footer; \ No newline at end of file diff --git a/src/components/Navbar.css b/src/components/Navbar.css new file mode 100644 index 0000000..2fc8309 --- /dev/null +++ b/src/components/Navbar.css @@ -0,0 +1,42 @@ +.navbar { + background-color: #ffffff; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + position: sticky; + top: 0; + z-index: 100; +} + +.navbar-container { + display: flex; + justify-content: space-between; + align-items: center; + height: 80px; +} + +.navbar-logo h1 { + font-size: 1.8rem; + color: #0066cc; + font-weight: 700; + margin: 0; +} + +.navbar-menu { + display: flex; + list-style: none; +} + +.navbar-item { + margin-left: 30px; +} + +.navbar-link { + color: #333; + font-weight: 500; + font-size: 1.1rem; + transition: color 0.3s ease; +} + +.navbar-link:hover { + color: #0066cc; + text-decoration: none; +} \ No newline at end of file diff --git a/src/components/Navbar.js b/src/components/Navbar.js new file mode 100644 index 0000000..2dbe25c --- /dev/null +++ b/src/components/Navbar.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import './Navbar.css'; + +function Navbar() { + return ( + + ); +} + +export default Navbar; \ No newline at end of file diff --git a/src/data/destinations.js b/src/data/destinations.js new file mode 100644 index 0000000..1ac5ef2 --- /dev/null +++ b/src/data/destinations.js @@ -0,0 +1,40 @@ +const destinations = [ + { + id: 1, + title: "Santorini, Greece", + description: "Santorini is one of the Cyclades islands in the Aegean Sea. It's known for its stunning white-washed buildings with blue domes, amazing sunsets and beautiful beaches with red and black volcanic sand.", + longDescription: "Santorini, officially known as Thira, is a volcanic island in the Cyclades group of the Greek islands. It's famous for its dramatic views, stunning sunsets, white-washed houses, and its own active volcano. The island is shaped like a crescent with the caldera lagoon in the middle.\n\nThe island's beauty has made it one of the most popular tourist destinations in Greece. Visitors can enjoy walking along the caldera cliff, visiting ancient sites, swimming in crystal-clear waters, and enjoying the local cuisine which includes unique products due to the volcanic soil.\n\nFira, the island's capital, and Oia, known for its spectacular sunsets, are the most famous villages. Santorini also has unique beaches due to its volcanic history, including Red Beach and Black Beach.", + image: "https://images.unsplash.com/photo-1570077188670-e3a8d69ac5ff?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + gallery: [ + "https://images.unsplash.com/photo-1613395877344-13d4a8e0d49e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + "https://images.unsplash.com/photo-1601581875309-fafbf2d3ed3a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + "https://images.unsplash.com/photo-1602580195841-d96bc18b702d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80" + ] + }, + { + id: 2, + title: "Kyoto, Japan", + description: "Kyoto, once the capital of Japan, is famous for its numerous classical Buddhist temples, gardens, imperial palaces, Shinto shrines and traditional wooden houses.", + longDescription: "Kyoto served as Japan's capital and the emperor's residence from 794 until 1868. It's now the country's seventh largest city and a major tourist destination. With its 2,000 religious buildings, including 1,600 Buddhist temples and 400 Shinto shrines, Kyoto is one of the best-preserved cities in Japan.\n\nThe city is also known for its beautiful gardens, its traditional kaiseki dining, and its geisha district of Gion. Among its most famous temples are Kinkaku-ji (Golden Pavilion), a Zen temple covered in gold leaf, and Ryoan-ji, home to Japan's most famous rock garden.\n\nVisitors to Kyoto can also enjoy the Arashiyama Bamboo Grove, the Fushimi Inari Shrine with its thousands of vermilion torii gates, and the historic district of Higashiyama.", + image: "https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + gallery: [ + "https://images.unsplash.com/photo-1528360983277-13d401cdc186?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + "https://images.unsplash.com/photo-1607619662634-3ac55ec0e216?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + "https://images.unsplash.com/photo-1493589976221-c2357c31ad77?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80" + ] + }, + { + id: 3, + title: "Machu Picchu, Peru", + description: "Machu Picchu is an Incan citadel set high in the Andes Mountains in Peru. Built in the 15th century and later abandoned, it's renowned for its sophisticated dry-stone walls and panoramic views.", + longDescription: "Machu Picchu stands 2,430 meters above sea level, in the middle of a tropical mountain forest, in an extraordinarily beautiful setting. It was probably the most amazing urban creation of the Inca Empire at its height; its giant walls, terraces and ramps seem as if they have been cut naturally in the continuous rock escarpments.\n\nThe natural setting, on the eastern slopes of the Andes, encompasses the upper Amazon basin with its rich diversity of flora and fauna. The Incas built the estate around 1450 but abandoned it a century later at the time of the Spanish Conquest.\n\nMachu Picchu was brought to international attention by Hiram Bingham in 1911 and was declared a UNESCO World Heritage site in 1983. The site is reached either by hiking the Inca Trail or by taking a train to Aguas Calientes and then a bus up the winding road to the entrance.", + image: "https://images.unsplash.com/photo-1526392060635-9d6019884377?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + gallery: [ + "https://images.unsplash.com/photo-1587595431973-160d0d94add1?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + "https://images.unsplash.com/photo-1548791694-a532cd3d0a70?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80", + "https://images.unsplash.com/photo-1459536516159-07a359f08be4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80" + ] + } +]; + +export default destinations; \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..6678ef4 --- /dev/null +++ b/src/index.css @@ -0,0 +1,27 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Montserrat', sans-serif; + line-height: 1.6; + color: #333; + background-color: #f8f8f8; +} + +a { + text-decoration: none; + color: #0066cc; +} + +a:hover { + text-decoration: underline; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 20px; +} \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..2758ef8 --- /dev/null +++ b/src/index.js @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import './index.css'; +import App from './App'; +import { BrowserRouter } from 'react-router-dom'; + +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render( + + + + + +); \ No newline at end of file diff --git a/src/pages/DestinationDetail.css b/src/pages/DestinationDetail.css new file mode 100644 index 0000000..2d5e4b4 --- /dev/null +++ b/src/pages/DestinationDetail.css @@ -0,0 +1,167 @@ +.destination-hero { + height: 500px; + background-size: cover; + background-position: center; + position: relative; + display: flex; + align-items: flex-end; + color: white; +} + +.destination-hero::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0.6)); +} + +.destination-hero h1 { + position: relative; + font-size: 3rem; + margin-bottom: 40px; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); +} + +.destination-content { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 40px; + margin: 60px 0; +} + +.destination-description h2 { + margin-bottom: 20px; + font-size: 1.8rem; + color: #333; +} + +.destination-description p { + margin-bottom: 20px; + line-height: 1.7; + color: #444; + font-size: 1.1rem; +} + +.back-btn { + margin-top: 20px; +} + +.destination-info-box { + background-color: #f8f8f8; + border-radius: 10px; + padding: 30px; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); +} + +.destination-info-box h3 { + margin-bottom: 20px; + color: #0066cc; + font-size: 1.3rem; +} + +.quick-facts { + list-style: none; +} + +.quick-facts li { + margin-bottom: 15px; + padding-bottom: 15px; + border-bottom: 1px solid #e0e0e0; +} + +.quick-facts li:last-child { + margin-bottom: 0; + padding-bottom: 0; + border-bottom: none; +} + +.destination-gallery h2 { + text-align: center; + margin-bottom: 30px; + font-size: 1.8rem; + color: #333; +} + +.gallery-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + margin-bottom: 60px; +} + +.gallery-item { + height: 250px; + border-radius: 8px; + overflow: hidden; +} + +.gallery-item img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.3s ease; +} + +.gallery-item:hover img { + transform: scale(1.05); +} + +.other-destinations h2 { + text-align: center; + margin-bottom: 30px; + font-size: 1.8rem; + color: #333; +} + +.other-destinations-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 30px; + margin-bottom: 60px; +} + +.error-container { + text-align: center; + padding: 80px 0; +} + +.error-container h2 { + margin-bottom: 20px; + font-size: 2rem; +} + +.error-container p { + margin-bottom: 30px; + color: #666; +} + +@media (max-width: 992px) { + .destination-content { + grid-template-columns: 1fr; + } + + .gallery-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + .destination-hero { + height: 350px; + } + + .destination-hero h1 { + font-size: 2.2rem; + } + + .other-destinations-grid { + grid-template-columns: 1fr; + } + + .gallery-grid { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/src/pages/DestinationDetail.js b/src/pages/DestinationDetail.js new file mode 100644 index 0000000..e63710d --- /dev/null +++ b/src/pages/DestinationDetail.js @@ -0,0 +1,90 @@ +import React from 'react'; +import { useParams, Link } from 'react-router-dom'; +import destinations from '../data/destinations'; +import './DestinationDetail.css'; + +function DestinationDetail() { + const { id } = useParams(); + const destination = destinations.find(dest => dest.id === parseInt(id)); + + if (!destination) { + return ( +
+

Destination not found

+

Sorry, we couldn't find the destination you're looking for.

+ Return to Home +
+ ); + } + + return ( +
+
+
+

{destination.title}

+
+
+ +
+
+
+

About {destination.title}

+ {destination.longDescription.split('\n\n').map((paragraph, index) => ( +

{paragraph}

+ ))} + + + Back to All Destinations + +
+ +
+
+

Quick Facts

+
    +
  • Location: {destination.title}
  • +
  • Best Time to Visit: Year-round, but Spring and Fall offer the best weather
  • +
  • Known For: Cultural heritage, natural beauty, local cuisine
  • +
+
+
+
+ +
+

Photo Gallery

+
+ {destination.gallery.map((image, index) => ( +
+ {`${destination.title} +
+ ))} +
+
+ +
+

Other Destinations You May Like

+
+ {destinations.filter(dest => dest.id !== parseInt(id)) + .slice(0, 2) + .map(dest => ( +
+
+ {dest.title} +
+
+

{dest.title}

+

{dest.description.substring(0, 100)}...

+ + Read More + +
+
+ ))} +
+
+
+
+ ); +} + +export default DestinationDetail; \ No newline at end of file diff --git a/src/pages/Home.css b/src/pages/Home.css new file mode 100644 index 0000000..de95e71 --- /dev/null +++ b/src/pages/Home.css @@ -0,0 +1,175 @@ +.hero { + background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80'); + background-size: cover; + background-position: center; + height: 500px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 60px; + border-radius: 10px; + text-align: center; + color: white; +} + +.hero-content { + max-width: 700px; + padding: 0 20px; +} + +.hero-content h2 { + font-size: 2.5rem; + margin-bottom: 20px; +} + +.hero-content p { + font-size: 1.2rem; + line-height: 1.7; +} + +.section-title { + text-align: center; + margin-bottom: 30px; + font-size: 2rem; + color: #333; +} + +.destinations-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); + gap: 30px; + margin-bottom: 60px; +} + +.destination-card { + background: white; + border-radius: 10px; + overflow: hidden; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.destination-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15); +} + +.destination-image { + height: 240px; + overflow: hidden; +} + +.destination-image img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; +} + +.destination-card:hover .destination-image img { + transform: scale(1.05); +} + +.destination-info { + padding: 20px; +} + +.destination-info h3 { + margin-bottom: 10px; + font-size: 1.4rem; +} + +.destination-info p { + color: #666; + margin-bottom: 20px; + line-height: 1.6; +} + +.btn { + display: inline-block; + background: #0066cc; + color: white; + padding: 10px 20px; + border-radius: 5px; + font-weight: 500; + text-transform: uppercase; + font-size: 0.9rem; + letter-spacing: 0.5px; + transition: background 0.3s ease; + border: none; + cursor: pointer; +} + +.btn:hover { + background: #0055aa; + text-decoration: none; + color: white; +} + +.cta-section { + background: linear-gradient(to right, #0066cc, #004e9c); + color: white; + border-radius: 10px; + padding: 60px 40px; + text-align: center; +} + +.cta-content { + max-width: 700px; + margin: 0 auto; +} + +.cta-content h2 { + margin-bottom: 20px; + font-size: 2rem; +} + +.cta-content p { + margin-bottom: 30px; + font-size: 1.1rem; +} + +.subscribe-form { + display: flex; + max-width: 500px; + margin: 0 auto; +} + +.subscribe-form input { + flex-grow: 1; + padding: 12px 20px; + border: none; + border-radius: 5px 0 0 5px; + font-size: 1rem; +} + +.subscribe-form .btn { + border-radius: 0 5px 5px 0; +} + +@media (max-width: 768px) { + .hero { + height: 400px; + } + + .hero-content h2 { + font-size: 2rem; + } + + .destinations-grid { + grid-template-columns: 1fr; + } + + .subscribe-form { + flex-direction: column; + } + + .subscribe-form input { + margin-bottom: 10px; + border-radius: 5px; + } + + .subscribe-form .btn { + border-radius: 5px; + } +} \ No newline at end of file diff --git a/src/pages/Home.js b/src/pages/Home.js new file mode 100644 index 0000000..b674928 --- /dev/null +++ b/src/pages/Home.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import destinations from '../data/destinations'; +import './Home.css'; + +function Home() { + return ( +
+

Explore Beautiful Destinations

+ +
+
+

Welcome to our Travel Blog

+

Discover amazing places around the world, get inspiration for your next adventure, and learn about different cultures and traditions.

+
+
+ +
+

Featured Destinations

+
+ {destinations.map(destination => ( +
+
+ {destination.title} +
+
+

{destination.title}

+

{destination.description}

+ + Read More + +
+
+ ))} +
+
+ +
+
+

Ready for your next adventure?

+

Subscribe to our newsletter and get travel tips, destination guides, and exclusive offers directly to your inbox.

+
+ + +
+
+
+
+ ); +} + +export default Home; \ No newline at end of file