Limucc-dev's picture
i cant see?
df4d34d verified
Raw
History Blame Contribute Delete
8.34 kB
x
/** @jsxImportSource react */
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
// Theme
const theme = {
colors: {
primary: '#3B82F6',
accent: '#10B981',
background: '#F9FAFB',
text: '#111827',
secondary: '#6366F1',
white: '#FFFFFF',
gray100: '#F3F4F6',
gray200: '#E5E7EB',
gray500: '#6B7280',
gray700: '#374151',
},
shadows: {
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
},
radii: {
sm: '4px',
md: '8px',
lg: '12px',
full: '9999px',
},
};
// Styled Components
const Container = styled.div`
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
`;
const MapContainer = styled.div`
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 0;
`;
const BottomSheet = styled.div`
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: ${theme.colors.white};
border-top-left-radius: ${theme.radii.lg};
border-top-right-radius: ${theme.radii.lg};
box-shadow: ${theme.shadows.lg};
padding: 16px;
padding-bottom: env(safe-area-inset-bottom, 16px);
transform: ${props => props.open ? 'translateY(0)' : 'translateY(80%)'};
transition: transform 0.3s ease-out;
z-index: 10;
max-height: 70vh;
overflow-y: auto;
`;
const ListingCard = styled.div`
background: ${theme.colors.white};
border-radius: ${theme.radii.md};
box-shadow: ${theme.shadows.sm};
padding: 12px;
margin-bottom: 12px;
transition: all 0.2s ease;
&:active {
transform: scale(0.98);
}
`;
// Main App Component
function App() {
const [map, setMap] = useState(null);
const [userLocation, setUserLocation] = useState(null);
const [showForm, setShowForm] = useState(false);
const [listings, setListings] = useState([]);
const [bottomSheetOpen, setBottomSheetOpen] = useState(true);
useEffect(() => {
// Initialize map
const mapInstance = L.map('map').setView([41.2995, 69.2401], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(mapInstance);
setMap(mapInstance);
// Get user location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
const { latitude, longitude } = position.coords;
setUserLocation({ lat: latitude, lng: longitude });
mapInstance.setView([latitude, longitude], 15);
// Add user marker
L.marker([latitude, longitude], {
icon: L.divIcon({
className: 'user-location-marker',
html: `<div style="background: ${theme.colors.primary}; width: 24px; height: 24px; border-radius: 50%; border: 3px solid white;"></div>`
})
}).addTo(mapInstance);
// Fetch nearby listings
fetchListings(latitude, longitude);
},
error => {
console.error('Geolocation error:', error);
// Default to Tashkent coordinates
setUserLocation({ lat: 41.2995, lng: 69.2401 });
fetchListings(41.2995, 69.2401);
}
);
}
return () => {
mapInstance.remove();
};
}, []);
const fetchListings = async (lat, lng) => {
try {
// Mock data for demo
const mockListings = [
{
id: '1',
title: 'Cozy Apartment for Students',
price: 300,
category: 'house',
tags: ['For students'],
description: 'Nice apartment near university',
lat: lat + 0.005,
lng: lng + 0.005,
images: ['http://static.photos/house/640x360/1']
},
{
id: '2',
title: 'Office Space for Rent',
price: 500,
category: 'office',
tags: ['For office staff'],
description: 'Modern office in business district',
lat: lat - 0.003,
lng: lng + 0.007,
images: ['http://static.photos/office/640x360/1']
}
];
setListings(mockListings);
// Add markers for listings
mockListings.forEach(listing => {
L.marker([listing.lat, listing.lng], {
icon: L.divIcon({
className: 'listing-marker',
html: `<div style="background: ${theme.colors.accent}; width: 20px; height: 20px; border-radius: 50%; border: 2px solid white;"></div>`
})
}).addTo(map).on('click', () => {
// Center map on listing
map.setView([listing.lat, listing.lng], 15);
});
});
} catch (error) {
console.error('Error fetching listings:', error);
}
};
return (
<Container>
<MapContainer id="map" />
<BottomSheet open={bottomSheetOpen}>
<div className="flex justify-between items-center mb-4">
<h2 className="text-lg font-semibold">Nearby Listings</h2>
<button
onClick={() => setBottomSheetOpen(!bottomSheetOpen)}
className="p-2 rounded-full hover:bg-gray-100"
>
<i data-feather={bottomSheetOpen ? "chevron-down" : "chevron-up"}></i>
</button>
</div>
<div className="space-y-3">
{listings.map(listing => (
<ListingCard key={listing.id}>
<div className="flex">
<div className="w-24 h-24 bg-gray-200 rounded-md overflow-hidden">
<img
src={listing.images[0]}
alt={listing.title}
className="w-full h-full object-cover"
/>
</div>
<div className="ml-3 flex-1">
<h3 className="font-medium">{listing.title}</h3>
<p className="text-sm text-gray-500 mt-1">${listing.price}/month</p>
<div className="flex items-center mt-2 text-sm text-gray-500">
<i data-feather="map-pin" className="w-3 h-3 mr-1"></i>
<span>1.2 km away</span>
</div>
</div>
</div>
</ListingCard>
))}
</div>
</BottomSheet>
{/* Floating action button for new listing */}
<button
className="fixed bottom-20 right-4 bg-blue-500 text-white p-3 rounded-full shadow-lg hover:bg-blue-600 transition-colors"
style={{ zIndex: 20 }}
onClick={() => setShowForm(true)}
>
<i data-feather="plus"></i>
</button>
{showForm && <listing-form></listing-form>}
</Container>
);
}
// Render the app
ReactDOM.render(<App />, document.getElementById('root'));