Skip to content

Commit

Permalink
Merge pull request #79 from Vizzuality/develop
Browse files Browse the repository at this point in the history
Mobile version
  • Loading branch information
barbara-chaves authored Nov 18, 2024
2 parents 77d0652 + 8c1cbf4 commit 6a44baa
Show file tree
Hide file tree
Showing 67 changed files with 3,584 additions and 2,277 deletions.
2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
"d3-array": "3.2.4",
"date-fns": "^3.3.1",
"deck.gl": "8.9.19",
"embla-carousel": "^8.3.0",
"embla-carousel-react": "^8.3.0",
"eslint": "8.42.0",
"eslint-config-next": "13.4.5",
"framer-motion": "^10.16.4",
Expand Down
4 changes: 2 additions & 2 deletions client/src/app/(landing)/globe/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ async function prefetchQueries(searchParams: HomePageProps['searchParams']) {
});

// Stories
let categoryId;
let categoryId: string | undefined;

// If there is a category in the search params, we need to get the category id to use as a category filter
if (searchParams.category) {
const categories = queryClient.getQueryData<CategoryListResponse>(categoriesQueryKey);

categoryId = categories?.data?.find((category) => {
return `"${category.attributes?.slug}"` === searchParams.category;
})?.id;
})?.attributes?.slug;
}

const params = getStoriesParams(categoryId ? { category: categoryId } : {});
Expand Down
26 changes: 0 additions & 26 deletions client/src/app/(landing)/stories/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,6 @@ import Story from '@/containers/story';

type StoryPageProps = { params: { id: string } };

// You can't generate static params for dynamic routes if they are using useSearchParams https://nextjs.org/docs/messages/deopted-into-client-rendering
// The solution is to wrap the component with Suspense
// By doing this, we will have errors related to hydration
// As we use it inside RecoilURLSyncNext, we can't generate static params

// export async function generateStaticParams() {
// try {
// const { data: storiesData } = await getStories({
// 'pagination[limit]': 200,
// });

// if (!storiesData) {
// throw new Error('Failed to parse storiesData');
// }

// console.log('storiesData', storiesData);

// return storiesData.map((s) => ({
// id: `${s.id}`,
// }));
// } catch (e) {
// console.error(e);
// return [];
// }
// }

export async function generateMetadata({ params }: StoryPageProps): Promise<Metadata> {
try {
// read route params
Expand Down
1 change: 0 additions & 1 deletion client/src/app/layout-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { PropsWithChildren, useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import { TooltipProvider } from '@/components/ui/tooltip';

import { notesESA, openSans } from '@/styles/fonts';

export default function Providers({ children }: PropsWithChildren) {
Expand Down
23 changes: 19 additions & 4 deletions client/src/components/map/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
import type { ViewState } from 'react-map-gl';
import { CustomMapProps } from './types';

export const DEFAULT_VIEW_STATE: Partial<ViewState> = {
export const DEFAULT_VIEW_STATE = {
zoom: 2,
latitude: 0,
longitude: 0,
pitch: 0,
bearing: 0,
padding: {
top: 0,
bottom: 0,
left: 0,
right: 0,
},
};

export const DEFAULT_MOBILE_ZOOM = 0.75;

export const DEFAULT_PROPS: CustomMapProps = {
id: 'default',
initialViewState: DEFAULT_VIEW_STATE,
minZoom: DEFAULT_MOBILE_ZOOM,
maxZoom: 14,
};
2 changes: 1 addition & 1 deletion client/src/components/map/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export const MapMapbox: FC<CustomMapProps> = ({
}, [bounds, isFlying]);

return (
<div className={cn('relative z-0 h-full w-full', className)}>
<div className={cn('relative z-0 h-full w-screen', className)}>
<ReactMapGL
id={id}
initialViewState={initialViewState}
Expand Down
113 changes: 70 additions & 43 deletions client/src/components/map/layers/marker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,99 @@
'use client';

import { Marker as RMarker } from 'react-map-gl';

import { XIcon } from 'lucide-react';

import { cn } from '@/lib/classnames';

import { useIsMobile } from '@/hooks/screen-size';

import { Button } from '@/components/ui/button';
import CategoryIcon from '@/components/ui/category-icon';

type MarkerProps = {
markers?: (GeoJSON.Feature<GeoJSON.Point> | null)[];
handleClick: (id: string | number) => void;
handleClose?: () => void;
};

const Marker = ({ markers, handleClick }: MarkerProps) => {
const Marker = ({ markers, handleClick, handleClose }: MarkerProps) => {
const { coordinates } = markers?.[0]?.geometry || {};

const isMobile = useIsMobile();

if (!coordinates?.length) return null;
return (
<RMarker anchor="left" latitude={coordinates[1]} longitude={coordinates[0]}>
<div className="flex items-center">

const MARKER = () => (
<div className="pointer-events-auto relative flex w-full items-center">
<div
className={cn({
'relative z-50 hidden h-6 w-6 -translate-x-1/2 cursor-pointer items-center justify-center sm:flex':
true,
})}
>
<div
className={cn({
'relative z-50 flex h-6 w-6 -translate-x-1/2 cursor-pointer items-center justify-center':
'absolute left-1/2 top-1/2 flex h-3 w-3 -translate-x-1/2 -translate-y-1/2 rotate-45 items-center justify-center border-[1.5px] border-[#FFE094] transition-all':
true,
'bg-background scale-[1.25] border-gray-200': true,
})}
>
<div
className={cn({
'absolute left-1/2 top-1/2 flex h-3 w-3 -translate-x-1/2 -translate-y-1/2 rotate-45 items-center justify-center border-[1.5px] border-[#FFE094] transition-all':
true,
'bg-background scale-[1.25] border-gray-200': true,
})}
>
<div className="h-[5px] w-[5px] bg-gray-200"></div>
</div>
<div className="h-[5px] w-[5px] bg-gray-200"></div>
</div>
</div>

<div className="max-w-[230px] -translate-x-6 rounded border border-gray-700 bg-[rgba(51,94,111,0.50)] px-0 text-white backdrop-blur-lg">
{markers?.map((marker) => {
if (!marker || !marker?.id) return null;
return (
<div
className="border-b border-b-gray-700 p-4 last-of-type:border-b-0"
key={marker.id}
onMouseMove={(e) => e.stopPropagation()}
>
<div className="mb-2 flex items-center space-x-4">
<CategoryIcon
slug={marker?.properties?.category}
className="h-10 w-10 fill-transparent stroke-teal-300 opacity-80"
/>
<p className="font-open-sans text-xs">{marker?.properties?.categoryName}</p>
</div>
<p className="font-notes text-sm">{marker?.properties?.title}</p>
<p className="font-open-sans mb-4 mt-2 text-xs italic text-gray-300">
{marker?.properties?.location}
</p>

<div className="mx-4 w-full max-w-full rounded border border-gray-700 bg-[rgba(51,94,111,0.50)] px-0 text-white backdrop-blur-lg sm:mx-0 sm:max-w-[230px] sm:-translate-x-6">
{markers?.map((marker) => {
if (!marker || !marker?.id) return null;
return (
<div
className="border-b border-b-gray-700 p-6 last-of-type:border-b-0 sm:py-4"
key={marker.id}
onMouseMove={(e) => e.stopPropagation()}
>
<div className="mb-2 flex items-center space-x-4">
<CategoryIcon
slug={marker?.properties?.category}
className="h-10 w-10 shrink-0 fill-transparent stroke-teal-300 opacity-80"
/>
<p className="font-open-sans text-xs">{marker?.properties?.categoryName}</p>
<Button
variant="secondary"
className="h-8 w-full rounded-3xl bg-teal-500 py-2 text-xs text-white hover:bg-teal-500/50"
onClick={() => !!marker.id && handleClick(marker.id)}
disabled={!marker?.properties?.active}
className="absolute right-0 top-0 sm:hidden"
size="icon"
variant="icon"
onClick={handleClose}
>
Discover story
<XIcon className="h-5 w-5" />
</Button>
</div>
);
})}
</div>
<p className="font-notes text-sm">{marker?.properties?.title}</p>
<p className="font-open-sans mb-4 mt-2 text-xs italic text-gray-300">
{marker?.properties?.location}
</p>

<Button
variant="secondary"
className="h-8 w-full rounded-3xl bg-teal-500 py-2 text-xs text-white hover:bg-teal-500/50"
onClick={() => !!marker.id && handleClick(marker.id)}
disabled={!marker?.properties?.active}
>
Discover story
</Button>
</div>
);
})}
</div>
</div>
);

return isMobile ? (
<div className="pointer-events-none absolute left-0 top-0 flex h-screen w-screen items-center justify-center">
<MARKER />
</div>
) : (
<RMarker anchor="left" latitude={coordinates[1]} longitude={coordinates[0]}>
<MARKER />
</RMarker>
);
};
Expand Down
41 changes: 17 additions & 24 deletions client/src/components/map/legend/index.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,44 @@
'use client';

import React, { useMemo, Children, isValidElement } from 'react';

import { ChevronDown } from 'lucide-react';

import { cn } from '@/lib/classnames';

import { useIsMobile } from '@/hooks/screen-size';

import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';

import SortableList from './sortable/list';
import { LegendProps } from './types';

export const Legend: React.FC<LegendProps> = ({
children,
className = '',
sortable,
onChangeOrder,
}: LegendProps) => {
export const Legend: React.FC<LegendProps> = ({ children, className = '' }: LegendProps) => {
const isChildren = useMemo(() => {
return !!Children.count(Children.toArray(children).filter((c) => isValidElement(c)));
}, [children]);

const isMobile = useIsMobile();

return (
isChildren && (
<div
className={cn({
'bg-card-map relative flex-col space-y-2 rounded-lg p-2 px-3 backdrop-blur-sm': true,
'bg-card-map relative flex-col space-y-2 rounded-lg p-4 backdrop-blur sm:backdrop-blur-sm':
true,
hidden: !isChildren,
[className]: !!className,
})}
>
{isChildren && (
<div className="flex flex-col gap-4 overflow-x-hidden">
{!!sortable?.enabled && !!onChangeOrder ? (
<SortableList sortable={sortable} onChangeOrder={onChangeOrder}>
<div className="flex flex-col overflow-x-hidden">
<Collapsible defaultOpen={!isMobile}>
<CollapsibleTrigger className="font-open-sans group flex w-full items-center justify-between gap-2 text-sm font-semibold text-white">
Legend <ChevronDown className="w-5 group-data-[state=closed]:rotate-180" />
</CollapsibleTrigger>
<CollapsibleContent className="flex flex-col overflow-x-hidden">
{children}
</SortableList>
) : Array.isArray(children) && children.length > 1 ? (
<Collapsible defaultOpen className="space-y-2">
<CollapsibleTrigger className="font-open-sans group flex w-full items-center justify-between gap-2 text-sm font-semibold text-white">
Legends <ChevronDown className="w-5 group-data-[state=closed]:rotate-180" />
</CollapsibleTrigger>
<CollapsibleContent className="flex flex-col gap-2 overflow-x-hidden">
{children}
</CollapsibleContent>
</Collapsible>
) : (
children
)}
</CollapsibleContent>
</Collapsible>
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const LegendTypeBasic: React.FC<LegendTypeProps> = ({
}) => {
return (
<div
className={cn({
className={cn('mt-3', {
[className]: !!className,
})}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const LegendTypeChoropleth: React.FC<LegendTypeProps> = ({
}) => {
return (
<div
className={cn('font-open', {
className={cn('font-open mt-3', {
[className]: !!className,
})}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const LegendTypeGradient: React.FC<LegendTypeProps> = ({
}) => {
return (
<div
className={cn({
className={cn('mt-3', {
[className || '']: !!className,
})}
>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/map/legend/item-types/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type LegendHeaderProps = {

const LegendHeader = ({ title, info }: LegendHeaderProps) => {
return (
<div className="font-open-sans mb-4 flex items-center justify-between gap-2 text-white">
<div className="font-open-sans mb-2 flex items-center justify-between gap-2 text-white">
{!!title && <div className="text-sm font-semibold text-white">{title}</div>}
{!!info && (
<Popover>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const LegendTypeMatrix: React.FC<LegendTypeProps & LegendMatrixIntersecti
intersections = [],
}) => {
return (
<div className="flex items-center space-x-14">
<div className="mt-3 flex items-center space-x-14">
<div className="relative ml-10 w-16 flex-shrink-0 py-12">
<p className="font-heading absolute left-1/2 top-1 -translate-x-1/2 transform text-xs font-medium text-white">
Always
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const LegendTypeSwitch = ({
);

return (
<div style={props.style} className="flex items-center justify-between gap-2">
<div style={props.style} className="mt-3 flex items-center justify-between gap-2">
<div className="flex">
<label
className="font-open-sans cursor-pointer text-sm text-white"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export const LegendTypeTimeline: React.FC<LegendTypeTimelineProps> = ({
}

return (
<div style={props?.style} className="z-30 mt-4">
<div style={props?.style} className="z-30 mt-3">
<LegendHeader title={title} info={info} />
<div className="flex items-center gap-8">
<Button
Expand Down
1 change: 0 additions & 1 deletion client/src/components/map/legend/item/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/component
import LegendItemToolbar from './toolbar';

export const LegendItem: React.FC<PropsWithChildren & LegendItemProps> = ({
id,
children,
name,
className = '',
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const buttonVariants = cva(
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
secondary: 'bg-secondary text-gray-200 hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
icon: '',
Expand Down
Loading

0 comments on commit 6a44baa

Please sign in to comment.