feat(ui): update UI v1

This commit is contained in:
fatemeh sane
2026-09-25 22:49:30 +03:30
parent 805f4594d4
commit 853ad67db5
82 changed files with 10311 additions and 505 deletions
+64
View File
@@ -0,0 +1,64 @@
import { useMemo } from 'react'
import { createPortal } from 'react-dom'
import { MdOpenInNew } from 'react-icons/md'
import { boundsForProjects, buildNeshanUrl, type MapProject } from '../data/mapProjects'
import { useLang } from '../i18n/lang'
import { MapViewport } from './MapViewport'
import { POPUP_PRIMARY_CLASS, ProjectPopupCard } from './ProjectPopupCard'
import { useMapLibre } from './useMapLibre'
import { useProjectMarkers } from './useProjectMarkers'
export type ProjectsMapSingleProps = {
/** همان پروژه‌ی شیت — یا محل جایگزین ساخته‌شده با createPlaceholderProject */
location: MapProject
/** تصاویر پروژه — همان آرایهٔ صفحهٔ جزئیات (تصویر شاخص + گالری) */
images?: string[]
/** ارتفاع/فاصله‌ها از بیرون — مثل «h-80» */
className?: string
}
/**
* نمای «تک‌پروژه» — یک سنجاق دقیق روی مختصات همان پروژه و پاپ‌آپی که فقط با
* کلیک کاربر باز می‌شود. تنها اکشن کارت، مشاهدهٔ آدرس پروژه در نشان است.
* جابه‌جایی نقشه به محدودهٔ همین پروژه بسته شده تا به بیرون نرود.
*/
export function ProjectsMapSingle({ location, images = [], className = '' }: ProjectsMapSingleProps) {
const { t } = useLang()
const projects = useMemo(() => [location], [location])
const bounds = useMemo(() => boundsForProjects(projects, 0.008), [projects])
const { containerRef, map, status, retry } = useMapLibre({
center: [location.lng, location.lat],
zoom: 15,
maxBounds: bounds,
})
const { popupHost, activeProject, closePopup } = useProjectMarkers(map, projects)
return (
<MapViewport
containerRef={containerRef}
map={map}
status={status}
onRetry={retry}
label={t('mapAria')}
className={className}
>
{popupHost &&
activeProject &&
createPortal(
<ProjectPopupCard project={activeProject} images={images} onClose={closePopup}>
{/* منطق دکمهٔ آدرس دست‌نخورده است — تنها اکشن این کارت */}
<a
href={buildNeshanUrl(activeProject)}
target="_blank"
rel="noopener noreferrer"
className={POPUP_PRIMARY_CLASS}
>
{t('viewAddress')}
<MdOpenInNew className="h-4 w-4" aria-hidden="true" />
</a>
</ProjectPopupCard>,
popupHost,
)}
</MapViewport>
)
}