Skip to content

Commit

Permalink
feat: new full screen map (#1083)
Browse files Browse the repository at this point in the history
* new full screen map
* set initial viewstate from user's geo
* migrate to route groups
  • Loading branch information
vnugent authored Jan 23, 2024
1 parent 977f11f commit 91fea75
Show file tree
Hide file tree
Showing 76 changed files with 322 additions and 57 deletions.
5 changes: 5 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ module.exports = {
},
async redirects () {
return [
{
source: '/map',
destination: '/maps',
permanent: true
},
{
source: '/areas/:uuid',
destination: '/area/:uuid/',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@turf/bbox": "^6.5.0",
"@turf/line-to-polygon": "^6.5.0",
"@udecode/zustood": "^1.1.3",
"@vercel/edge": "^1.1.1",
"auth0": "^2.42.0",
"awesome-debounce-promise": "^2.1.0",
"aws-sdk": "^2.1265.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AreaPageContainer } from '@/app/components/ui/AreaPageContainer'
import { AreaPageContainer } from '@/app/(default)/components/ui/AreaPageContainer'

/**
* Loading skeleton for /area/<id> page.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import Markdown from 'react-markdown'

import PhotoMontage, { UploadPhotoCTA } from '@/components/media/PhotoMontage'
import { getArea } from '@/js/graphql/getArea'
import { StickyHeaderContainer } from '@/app/components/ui/StickyHeaderContainer'
import { StickyHeaderContainer } from '@/app/(default)/components/ui/StickyHeaderContainer'
import { AreaCrumbs } from '@/components/breadcrumbs/AreaCrumbs'
import { ArticleLastUpdate } from '@/components/edit/ArticleLastUpdate'
import { getMapHref, getFriendlySlug, getAreaPageFriendlyUrl, sanitizeName } from '@/js/utils'
import { LazyAreaMap } from '@/components/maps/AreaMap'
import { AreaPageContainer } from '@/app/components/ui/AreaPageContainer'
import { AreaPageContainer } from '@/app/(default)/components/ui/AreaPageContainer'
import { AreaPageActions } from '../../components/AreaPageActions'
import { SubAreasSection } from './sections/SubAreasSection'
import { ClimbListSection } from './sections/ClimbListSection'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ClimbList } from '@/app/editArea/[slug]/general/components/climb/ClimbListForm'
import { ClimbList } from '@/app/(default)/editArea/[slug]/general/components/climb/ClimbListForm'
import { AreaType } from '@/js/types'
/**
* Climb list section
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Link from 'next/link'
import { PlusSquare } from '@phosphor-icons/react/dist/ssr'
import { AreaList } from 'app/editArea/[slug]/general/components/AreaList'
import { AreaList } from '@/app/(default)/editArea/[slug]/general/components/AreaList'
import { AreaEntityBullet } from '@/components/cues/Entities'
import { AreaType } from '@/js/types'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Link from 'next/link'
import { PencilSimple, ArrowElbowLeftDown } from '@phosphor-icons/react/dist/ssr'
import { ShareAreaLinkButton } from '@/app/components/ShareAreaLinkButton'
import { ShareAreaLinkButton } from '@/app/(default)/components/ShareAreaLinkButton'
import { UploadPhotoButton } from '@/components/media/PhotoUploadButtons'

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
'use client'
import { signIn, useSession } from 'next-auth/react'

import { Logo } from 'app/header'
import { Logo } from '../header'
import { XSearchMinimal } from '@/components/search/XSearch'
import { NavMenuItem, NavMenuItemProps } from '@/components/ui/NavMenuButton'
import GitHubStars from '@/components/GitHubStars'
import ProfileNavButton from './ProfileNavButton'
import AuthenticatedProfileNavButton from '../../../components/AuthenticatedProfileNavButton'

export const DesktopHeader: React.FC = () => {
const { status } = useSession()
Expand Down Expand Up @@ -56,7 +56,7 @@ export const DesktopHeader: React.FC = () => {
let nav
switch (status) {
case 'authenticated':
nav = <ProfileNavButton isMobile={false} />
nav = <AuthenticatedProfileNavButton isMobile={false} />
break
case 'loading':
nav = (
Expand Down
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions src/app/(default)/components/LandingHero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ArrowRight } from '@phosphor-icons/react/dist/ssr'

export const LandingHero: React.FC = () => {
return (
<section className='w-full px-6 py-4'>
<h1 className='text-2xl tracking-tighter font-semibold'>Share your climbing route knowledge!</h1>
<div className='font-medium text-neutral/80'>
Join us to help improve this comprehensive climbing resource for the community.
</div>
<div className='mt-2'>
<HeroAlert />
</div>
</section>
)
}

export const HeroAlert: React.FC = () => (
<div className='mt-2 alert alert-warning'>
<span className='badge badge-sm badge-primary'>NEW</span>
<a href='/maps' className='underline flex items-center gap-1 text-sm'>Crag maps<ArrowRight size={20} /></a>
</div>)
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
'use client'
import { useSession } from 'next-auth/react'
import { Logo } from 'app/header'
import { Logo } from '../header'
import { XSearchMinimal } from '@/components/search/XSearch'
import { LoginButton, More } from '@/components/MobileAppBar'
import ProfileNavButton from './ProfileNavButton'
import AuthenticatedProfileNavButton from '../../../components/AuthenticatedProfileNavButton'

/**
* Main header for mobile
*/
export const MobileHeader: React.FC = () => {
const { status } = useSession()
const nav = status === 'authenticated' ? <ProfileNavButton /> : <LoginButton />
const nav = status === 'authenticated' ? <AuthenticatedProfileNavButton /> : <LoginButton />
return (
<header className='flex lg:hidden items-center justify-between gap-6'>
<Logo />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Logo, LogoSize } from 'app/header'
import { Logo, LogoSize } from '../header'
/**
* Page footer
*/
export const PageFooter: React.FC = () => {
return (
<footer className='footer p-10 bg-base-200 bg-base-content text-base-100 snap-start snap-normal'>
<footer className='relative footer p-10 bg-base-200 bg-base-content text-base-100 snap-start snap-normal'>
<aside>
<div className='border-2 border-accent py-3 pl-2 pr-4 rounded-full'><Logo size={LogoSize.md} className='fill-accent' /></div>
<p><span className='font-semibold text-lg'>OpenBeta</span><br /><span className='tracking-tight font-sm'>Free climbing database built & run by climbers.</span></p>
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { GallerySkeleton } from '@/components/media/PhotoMontage'
import React from 'react'
import { AreaPageActionsSkeleton } from '../AreaPageActions'
import { HeroAlert } from '../LandingHero'

/**
* Area page containter. Show loading skeleton if no params are provided.
Expand All @@ -14,7 +15,10 @@ export const AreaPageContainer: React.FC<{
}> = ({ photoGallery, pageActions, breadcrumbs, map, children }) => {
return (
<article>
<div className='p-4 mx-auto max-w-5xl xl:max-w-7xl'>
<div className='px-4 mb-2'>
<HeroAlert />
</div>
<div className='px-4 mx-auto max-w-5xl xl:max-w-7xl'>
{photoGallery == null ? <GallerySkeleton /> : photoGallery}
<div className='flex justify-end py-4 border-b'>
{pageActions == null ? <AreaPageActionsSkeleton /> : pageActions}
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 5 additions & 2 deletions src/app/edit/page.tsx → src/app/(default)/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { getChangeHistoryServerSide } from '../../js/graphql/contribAPI'
import RecentChangeHistory from '@/components/edit/RecentChangeHistory'
import { ReactElement } from 'react'
import { Metadata } from 'next'

import { getChangeHistoryServerSide } from '@/js/graphql/contribAPI'
import RecentChangeHistory from '@/components/edit/RecentChangeHistory'

export const metadata: Metadata = {
title: 'Contribute to OpenBeta',
description: 'Share your climbing adventure photos and contribute to the climbing route catalog.'
}

export const revalidate = 3600

export default async function Page (): Promise<ReactElement> {
const history = await getChangeHistoryServerSide()
return (
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useSession } from 'next-auth/react'
import { useRouter } from 'next/navigation'
import { WarningOctagon } from '@phosphor-icons/react/dist/ssr'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import { DashboardInput } from '@/components/ui/form/Input'
import useUpdateAreasCmd from '@/js/hooks/useUpdateAreasCmd'
import { AreaType } from '@/js/types'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'
import { useSession } from 'next-auth/react'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import { AREA_DESCRIPTION_FORM_VALIDATION_RULES } from '@/components/edit/EditAreaForm'
import useUpdateAreasCmd from '@/js/hooks/useUpdateAreasCmd'
import { MarkdownTextArea } from '@/components/ui/form/MarkdownTextArea'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'
import { useSession } from 'next-auth/react'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import { AREA_LATLNG_FORM_VALIDATION_RULES } from '@/components/edit/EditAreaForm'
import { DashboardInput } from '@/components/ui/form/Input'
import useUpdateAreasCmd from '@/js/hooks/useUpdateAreasCmd'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { useSession } from 'next-auth/react'
import { ValidationValueMessage } from 'react-hook-form'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import { DashboardInput } from '@/components/ui/form/Input'
import useUpdateAreasCmd from '@/js/hooks/useUpdateAreasCmd'
import { AREA_NAME_FORM_VALIDATION_RULES } from '@/components/edit/EditAreaForm'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { useSession } from 'next-auth/react'
import { useRouter } from 'next/navigation'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import useUpdateAreasCmd from '@/js/hooks/useUpdateAreasCmd'
import { AreaType } from '@/js/types'
import { AreaDesignationRadioGroup, areaDesignationToDb, areaDesignationToForm, AreaTypeFormProp } from '@/components/edit/form/AreaDesignationRadioGroup'
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default async function EditAreaDashboardLayout ({
}): Promise<any> {
const { area: { uuid, pathTokens, ancestors, areaName, metadata: { leaf } } } = await getPageDataForEdit(params.slug)
return (
<div>
<div className='relative w-full h-full'>
<div className='px-12 pt-8 pb-4'>
<div className='text-3xl tracking-tight font-semibold'>Edit area</div>

Expand All @@ -35,7 +35,7 @@ export default async function EditAreaDashboardLayout ({
</div>
<div className='flex bg-base-200 flex-col lg:flex-row py-12'>
<SidebarNav slug={params.slug} canAddAreas={!leaf} canAddClimbs={leaf} />
<main className='w-full px-2 lg:px-16'>
<main className='relative h-full w-full px-2 lg:px-16'>
{children}
</main>
</div>
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { SortableContext, rectSortingStrategy, sortableKeyboardCoordinates, arra
import clx from 'classnames'
import { DotsSixVertical } from '@phosphor-icons/react/dist/ssr'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import { AreaType } from '@/js/types'
import { areaLeftRightIndexComparator } from '@/js/utils'
import { SortableClimbItem } from '../../../manageClimbs/components/sorting/SortableClimbItem'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { useSession } from 'next-auth/react'
import { useRouter } from 'next/navigation'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import useUpdateClimbsCmd from '@/js/hooks/useUpdateClimbsCmd'
import { DynamicClimbInputList } from './DynamicClimbInputList'
import { GradeContexts } from '@/js/grades/Grade'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { SortableContext, rectSortingStrategy, sortableKeyboardCoordinates, arra
import clx from 'classnames'
import { DotsSixVertical } from '@phosphor-icons/react/dist/ssr'

import { SingleEntryForm } from 'app/editArea/[slug]/components/SingleEntryForm'
import { SingleEntryForm } from '@/app/(default)/editArea/[slug]/components/SingleEntryForm'
import { ClimbType } from '@/js/types'
import { climbLeftRightIndexComparator } from '@/js/utils'
import { SortableClimbItem } from './SortableClimbItem'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Metadata } from 'next'
import { DashboardPageProps, getPageDataForEdit } from '../general/page'
import { PageContainer, SectionContainer } from '../components/EditAreaContainers'
import { AddClimbsForm } from './components/AddClimbsForm'
import { ClimbListSection } from '@/app/area/[[...slug]]/sections/ClimbListSection'
import { ClimbListSection } from '@/app/(default)/area/[[...slug]]/sections/ClimbListSection'
import { SortClimbsForm } from './components/sorting/SortClimbsForm'

// Opt out of caching for all data requests in the route segment
Expand Down
File renamed without changes.
File renamed without changes.
10 changes: 5 additions & 5 deletions src/app/layout.tsx → src/app/(default)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Metadata } from 'next'
import '../../public/fonts/fonts.css'
import './global.css'
import '@/public/fonts/fonts.css'
import '../global.css'
import Header from './header'
import { PageFooter } from './components/PageFooter'
import { NextAuthProvider } from './components/NextAuthProvider'
import { NextAuthProvider } from '@/components/auth/NextAuthProvider'
import { ReactToastifyProvider } from './components/ReactToastifyProvider'
import { BlockingAlertUploadingInProgress } from './components/ui/GlobalAlerts'

Expand All @@ -26,8 +26,8 @@ export default function RootLayout ({
children: React.ReactNode
}): any {
return (
<html lang='en' className='snap-proximity snap-y'>
<body>
<html lang='en' className='snap-proximity snap-y scroll-smooth'>
<body className='relative'>
<NextAuthProvider>
<Header />
<div>
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/app/page.tsx → src/app/(default)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { RecentContributionsMap } from './components/recent/RecentContributionsM
/**
* Cache duration in seconds
*/
export const revalidate = 3600
export const dynamic = 'force-dynamic'

/**
* Root home page
Expand Down
17 changes: 17 additions & 0 deletions src/app/(maps)/components/ProfileMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client'
import { SessionProvider } from 'next-auth/react'
import { House } from '@phosphor-icons/react/dist/ssr'
import AuthenticatedProfileNavButton from '@/components/AuthenticatedProfileNavButton'

export const ProfileMenu: React.FC = () => {
return (
<SessionProvider>
<div className='absolute right-4 top-4 z-50'>
<nav className='flex items-center gap-2'>
<a className='btn glass' href='/'><House size={18} />Home</a>
<AuthenticatedProfileNavButton isMobile={false} />
</nav>
</div>
</SessionProvider>
)
}
31 changes: 31 additions & 0 deletions src/app/(maps)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'mapbox-gl/dist/mapbox-gl.css'
import { Metadata } from 'next'
import '@/public/fonts/fonts.css'
import './../global.css'

/**
* Root layout for `/maps` route
*/
export default function MapsRootLayout ({
children
}: {
children: React.ReactNode
}): any {
return (
<html lang='en'>
<body className='relative'>
{children}
</body>
</html>
)
}

export const metadata: Metadata = {
title: 'Open climb maps',
description: 'Free rock climbing platform',
openGraph: {
description: 'OpenBeta is a free climbing platform. Join the community and share your knowledge today.',
images: '/south-africa-og.jpeg'
},
metadataBase: new URL(`https://${process.env.VERCEL_URL ?? 'http://localhost:3000'}`)
}
15 changes: 15 additions & 0 deletions src/app/(maps)/maps/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { GlobalMap } from '@/components/maps/GlobalMap'
import { ProfileMenu } from '../components/ProfileMenu'

export const dynamic = 'force-dynamic'

export default async function MapPage (): Promise<any> {
return (
<div className='w-full h-full'>
<ProfileMenu />
<GlobalMap
showFullscreenControl={false}
/>
</div>
)
}
18 changes: 18 additions & 0 deletions src/app/api/geo/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from 'next/server'
import { geolocation } from '@vercel/edge'

export const runtime = 'edge'

/**
* Return latitude and longitude of the visitor. Only works when deploying on Vercel.
* Endpoint: `/api/geo`
*/
export async function GET (request: NextRequest): Promise<any> {
const geo = geolocation(request)
const longitude = geo?.longitude
const latitude = geo?.latitude
if (longitude != null && latitude != null) {
return NextResponse.json({ longitude: parseFloat(longitude), latitude: parseFloat(latitude) }, { status: 200 })
}
return NextResponse.json({ message: 'No geo data available.' }, { status: 503 })
}
Loading

1 comment on commit 91fea75

@vercel
Copy link

@vercel vercel bot commented on 91fea75 Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.