Skip to content

Commit

Permalink
refactor & handle more area data
Browse files Browse the repository at this point in the history
  • Loading branch information
vnugent committed May 25, 2024
1 parent 785b0fc commit ad9aa18
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 81 deletions.
6 changes: 3 additions & 3 deletions src/components/maps/CardGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export const MiniCarousel: React.FC<{ mediaList: MediaWithTagsInMapTile[] }> = (
const isSingle = mediaList.length === 1
return (
<section className='overflow-hidden relative' ref={emblaRef}>
<div className='flex h-28 gap-x-1'>
{mediaList.map((m) => (<Slide key={m._id} media={m} isSingle={isSingle} />))}
<div className='flex h-40 gap-x-1'>
{mediaList.map((m) => (<Slide key={m.mediaUrl} media={m} isSingle={isSingle} />))}
</div>
{!isSingle && (
<div className='absolute top-0 left-0 w-full h-full flex justify-between'>
Expand All @@ -46,7 +46,7 @@ export const MiniCarousel: React.FC<{ mediaList: MediaWithTagsInMapTile[] }> = (
const Slide: React.FC<{ media: MediaWithTagsInMapTile, isSingle: boolean }> = ({ media, isSingle }) => {
const { mediaUrl, width, height } = media
return (
<div className={clx('grow-0 shrink-0 min-w-0 h-28 bg-base-200',
<div className={clx('grow-0 shrink-0 min-w-0 h-40 bg-base-200',
isSingle ? 'basis-full' : 'basis-5/6'
)}
>
Expand Down
13 changes: 8 additions & 5 deletions src/components/maps/GlobalMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import maplibregl, { MapLibreEvent } from 'maplibre-gl'
import dynamic from 'next/dynamic'

import { MAP_STYLES, type MapStyles } from './MapSelector'
import { AreaInfoDrawer } from './TileHandlers/AreaInfoDrawer'
import { AreaInfoHover } from './TileHandlers/AreaInfoHover'
import { AreaInfoDrawer } from './TileHandlers/AreaDrawer'
import { AreaHoverCard } from './TileHandlers/AreaHoverCard'
import { OBCustomLayers } from './OBCustomLayers'
import { tileToFeature } from './utils'
import { ActiveFeature, TileProps } from './TileTypes'
Expand Down Expand Up @@ -134,7 +134,6 @@ export const GlobalMap: React.FC<GlobalMapProps> = ({
if (obLayerId !== -1) {
setCursor('pointer')
const feature = event.features?.[obLayerId]
console.log('#Hover', feature)

if (feature != null && mapInstance != null) {
const { layer, geometry, properties } = feature
Expand All @@ -154,7 +153,11 @@ export const GlobalMap: React.FC<GlobalMapProps> = ({
id: feature.id
}, { hover: true })

setHoverInfo(tileToFeature(layer.id, event.point, geometry, properties as TileProps, mapInstance))
const feat = tileToFeature(layer.id, event.point, geometry, properties as TileProps, mapInstance)

console.log('#props', feat)

setHoverInfo(feat)
}
} else {
setHoverInfo(null)
Expand Down Expand Up @@ -210,7 +213,7 @@ export const GlobalMap: React.FC<GlobalMapProps> = ({
<SelectedFeature feature={clickInfo} />}
<AreaInfoDrawer feature={clickInfo} />
{hoverInfo != null && (
<AreaInfoHover
<AreaHoverCard
{...hoverInfo}
onClick={onHoverCardClick}
/>)}
Expand Down
10 changes: 5 additions & 5 deletions src/components/maps/OBCustomLayers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const OBCustomLayers: React.FC<OBCustomLayersProps> = ({ layersState }) =
tiles={[
'https://maptiles.openbeta.io/areas/{z}/{x}/{y}.pbf'
]}
promoteId='uuid'
promoteId='id'
maxzoom={8}
attribution='© OpenBeta contributors'
>
Expand All @@ -32,11 +32,11 @@ export const OBCustomLayers: React.FC<OBCustomLayersProps> = ({ layersState }) =
'case',
['boolean', ['feature-state', 'hover'], false],
'#ec407a',
'#6366f1'
'#004F6E'
],
'line-width': { stops: [[6, 0.5], [8, 4]] },
'line-opacity': 0.65,
'line-dasharray': [2, 0.5]
'line-width': { stops: [[6, 2], [6.1, 4]] },
'line-blur': 4,
'line-opacity': 0.8

}}
layout={{
Expand Down
50 changes: 50 additions & 0 deletions src/components/maps/TileHandlers/AreaContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import Link from 'next/link'
import { CragGroupFeatureProps, SubArea } from '../TileTypes'
import { getAreaPageFriendlyUrl } from '@/js/utils'
import { Card } from '../../core/Card'
import { EntityIcon } from '@/app/(default)/editArea/[slug]/general/components/AreaItem'
import { MiniCarousel } from '../CardGallery'

export const AreaPanelContent: React.FC<CragGroupFeatureProps> = ({ id, areaName: name, subareas }) => {
const editUrl = `/editArea/${id}/general`
return (
<Card>
<div className='flex flex-col gap-4'>
<section className='flex flex-col gap-y-2'>
<Link className='text-lg font-medium leading-snug tracking-tight hover:underline' href={getAreaPageFriendlyUrl(id, name)}>{name}</Link>
<Subheading subareas={subareas} />
</section>

<a className='btn btn-primary btn-outline btn-sm no-animation' href={editUrl}>Edit area</a>

<hr />
</div>
</Card>
)
}

export const AreaHoverCardContent: React.FC<CragGroupFeatureProps> = ({ id, areaName: name, subareas, media }) => {
return (
<Card image={<MiniCarousel mediaList={media} />}>
<a
href={getAreaPageFriendlyUrl(id, name)}
className='text-base font-medium tracking-tight hover:underline'
onClick={(e) => e.stopPropagation()}
>
{name}
</a>
<Subheading subareas={subareas} />
</Card>
)
}

const Subheading: React.FC<{ subareas: SubArea[] }> = ({ subareas }) => {
return (
<div className='font-sm text-secondary flex items-center gap-4'>
<span className='bg-area-cue/80 text-base-100 p-1'>
<EntityIcon type='area' size={16} />
</span>
<span className='text-xs uppercase'><b>{subareas.length}</b> Sub-areas</span>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as Popover from '@radix-ui/react-popover'

import { ActiveFeature, CragFeatureProperties, CragGroupFeatureProps } from '../TileTypes'
import { CragPanelContent } from './CragPanelContent'
import { CragGroupPanelContent } from './CragGroupPanelContent'
import { CragPanelContent } from './CragContent'
import { AreaPanelContent } from './AreaContent'

/**
* Area info panel
Expand All @@ -16,7 +16,7 @@ export const AreaInfoDrawer: React.FC<{ feature: ActiveFeature | null, onClose?:
ContentComponent = <CragPanelContent {...(feature.data as CragFeatureProperties)} />
break
case 'area-boundaries':
ContentComponent = <CragGroupPanelContent {...(feature.data as CragGroupFeatureProps)} />
ContentComponent = <AreaPanelContent {...(feature.data as CragGroupFeatureProps)} />
break
default:
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import { Card } from '../../core/Card'
import { EntityIcon } from '@/app/(default)/editArea/[slug]/general/components/AreaItem'
import { ActiveFeature, CragFeatureProperties, CragGroupFeatureProps } from '../TileTypes'
import { MiniCarousel } from '../CardGallery'
import { AreaHoverCardContent } from './AreaContent'

/**
* Area info panel.
* Area hover card.
* By default a mouse click on the panel will select the
* underlying feature and activate the side drawer. For links/buttons
* we need to call event.stopPropagation() to prevent the panel from
* receiving the click event.
*/
export const AreaInfoHover: React.FC<ActiveFeature & {
export const AreaHoverCard: React.FC<ActiveFeature & {
/**
* Handle click event on the popover
*/
Expand All @@ -26,11 +27,11 @@ export const AreaInfoHover: React.FC<ActiveFeature & {
case 'crag-markers':
case 'crag-name-labels':
screenXY = mapInstance.project(geometry.coordinates)
ContentComponent = <Content {...(data as CragFeatureProperties)} />
ContentComponent = <CragHoverCardContent {...(data as CragFeatureProperties)} />
break
case 'area-boundaries':
screenXY = point
ContentComponent = <CragGroupContent {...(data as CragGroupFeatureProps)} />
ContentComponent = <AreaHoverCardContent {...(data as CragGroupFeatureProps)} />
break
default:
return null
Expand All @@ -42,7 +43,8 @@ export const AreaInfoHover: React.FC<ActiveFeature & {
<Popover.Content
align='center'
side='top'
sideOffset={8}
sideOffset={2}
sticky='always'
collisionPadding={24}
className='z-50 focus:outline-none cursor-pointer'
onClick={(e) => {
Expand All @@ -56,7 +58,7 @@ export const AreaInfoHover: React.FC<ActiveFeature & {
)
}

export const Content: React.FC<CragFeatureProperties> = ({ id, areaName, climbs, media }) => {
export const CragHoverCardContent: React.FC<CragFeatureProperties> = ({ id, areaName, climbs, media }) => {
return (
<Card image={<MiniCarousel mediaList={media} />}>
<div className='flex flex-col gap-y-1 text-xs'>
Expand All @@ -76,22 +78,3 @@ export const Content: React.FC<CragFeatureProperties> = ({ id, areaName, climbs,
</Card>
)
}

const CragGroupContent: React.FC<CragGroupFeatureProps> = ({ uuid: id, areaName: name, children }) => {
return (
<Card>
<a
href={getAreaPageFriendlyUrl(id, name)}
className='text-base font-medium tracking-tight hover:underline'
onClick={(e) => e.stopPropagation()}
>
{name}
</a>
<div className='font-sm text-secondary flex items-center gap-1'>
<EntityIcon type='area' size={16} />
·
<span className='text-xs'>{children.length} crags</span>
</div>
</Card>
)
}
29 changes: 0 additions & 29 deletions src/components/maps/TileHandlers/CragGroupPanelContent.tsx

This file was deleted.

29 changes: 20 additions & 9 deletions src/components/maps/TileTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,38 @@ export interface CragTileProps {
}

export interface CragGroupTileProps {
uuid: string
id: string
areaName: string
children: string
pathTokens: string
ancestors: string
media: string // stringified json
children: string // stringified json
content: string // stringified json
}

export type SimpleClimbType = Pick<ClimbType, 'id' | 'name' | 'type'>

export type MediaWithTagsInMapTile = Omit<MediaWithTags, 'id'> & { _id: string }
export type CragFeatureProperties = Pick<AreaType, 'id' | 'areaName' | 'content' | 'ancestors' | 'pathTokens'> & {
climbs: SimpleClimbType[]
export type MediaWithTagsInMapTile = MediaWithTags

type AreaFeatureProperties = Pick<AreaType, 'id' | 'areaName' | 'content' | 'ancestors' | 'pathTokens'> & {
media: MediaWithTagsInMapTile[]
}

export type CragFeatureProperties = AreaFeatureProperties & {
climbs: SimpleClimbType[]
}
export interface SimpleCragType {
uuid: string
id: string
areaName: string
}

export interface CragGroupFeatureProps {
uuid: string
export interface SubArea {
id: string
areaName: string
children: SimpleCragType[]
}
export interface CragGroupFeatureProps extends AreaFeatureProperties {
subareas: SubArea[]
media: MediaWithTagsInMapTile[]
}

export type FeatureProps = CragGroupFeatureProps | CragFeatureProperties
Expand Down
9 changes: 7 additions & 2 deletions src/components/maps/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MapInstance } from 'react-map-gl/maplibre'
import { Geometry } from 'geojson'
import { CragFeatureProperties, CragGroupFeatureProps, SimpleClimbType, CragGroupTileProps, CragTileProps, ActiveFeature } from './TileTypes'
import { CragFeatureProperties, CragGroupFeatureProps, SimpleClimbType, CragGroupTileProps, CragTileProps, ActiveFeature, SubArea, MediaWithTagsInMapTile } from './TileTypes'

/**
* Convert maplibre tile feature to our model
Expand Down Expand Up @@ -49,8 +49,13 @@ const transformCragTileProps = (props: CragTileProps): CragFeatureProperties =>
}

const transformCragGroupTileProps = (props: CragGroupTileProps): CragGroupFeatureProps => {
const { children, media, ancestors, pathTokens } = props
return {
...props,
children: []// JSON.parse(children) as SimpleCragType[]
ancestors: JSON.parse(ancestors) as string[],
pathTokens: JSON.parse(pathTokens) as string[],
content: JSON.parse(props?.content ?? {}),
subareas: JSON.parse(children) as SubArea[],
media: JSON.parse(media) as MediaWithTagsInMapTile[]
}
}

0 comments on commit ad9aa18

Please sign in to comment.