Skip to content

Commit

Permalink
Mobile version (#75)
Browse files Browse the repository at this point in the history
* Mobile version
  • Loading branch information
barbara-chaves authored Oct 29, 2024
1 parent 12a01b6 commit d7e3b94
Show file tree
Hide file tree
Showing 36 changed files with 1,288 additions and 471 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
12 changes: 7 additions & 5 deletions client/src/components/map/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ export const DEFAULT_VIEW_STATE = {
pitch: 0,
bearing: 0,
padding: {
top: 50,
bottom: 50,
left: 50,
right: 50,
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: 1,
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
109 changes: 66 additions & 43 deletions client/src/components/map/layers/marker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,69 +4,92 @@ import { cn } from '@/lib/classnames';

import { Button } from '@/components/ui/button';
import CategoryIcon from '@/components/ui/category-icon';
import { useBreakpoint } from '@/hooks/screen-size';
import { XIcon } from 'lucide-react';

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 = !useBreakpoint()('sm');

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 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="max-w-[230px] rounded border border-gray-700 bg-[rgba(51,94,111,0.50)] px-0 text-white backdrop-blur-lg sm:-translate-x-6">
{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 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"
size="icon"
variant="ghost"
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
35 changes: 13 additions & 22 deletions client/src/components/map/legend/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ import { ChevronDown } from 'lucide-react';

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

import { useBreakpoint } 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 breakpoint = useBreakpoint();
const isMobile = !breakpoint('sm');

return (
isChildren && (
<div
Expand All @@ -30,22 +29,14 @@ export const Legend: React.FC<LegendProps> = ({
>
{isChildren && (
<div className="flex flex-col overflow-x-hidden">
{!!sortable?.enabled && !!onChangeOrder ? (
<SortableList sortable={sortable} onChangeOrder={onChangeOrder}>
<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>
<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}
</CollapsibleContent>
</Collapsible>
) : (
<div className="-mt-3">{children}</div>
)}
</CollapsibleContent>
</Collapsible>
</div>
)}
</div>
Expand Down
115 changes: 115 additions & 0 deletions client/src/components/ui/carousel/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@

.embla {
margin: auto;
--slide-height: 19rem;
--slide-spacing: 2rem;
--slide-size: 80%;
}
.embla__viewport {
overflow: hidden;
}
.embla__container {
display: flex;
touch-action: pan-y pinch-zoom;
/* margin-left: calc(var(--slide-spacing) * -1); */
}
.embla__slide {
transform: translate3d(0, 0, 0);
/* flex: 0 0 var(--slide-size); */
min-width: 0;
/* padding-left: var(--slide-spacing); */
}

.embla__slide__number {
box-shadow: inset 0 0 0 0.2rem black;
border-radius: 1.8rem;
font-size: 4rem;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
height: var(--slide-height);
user-select: none;
}
.embla__controls {
display: grid;
grid-template-columns: auto 1fr;
justify-content: space-between;
gap: 1.2rem;
margin-top: 1.8rem;
}
.embla__buttons {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.6rem;
align-items: center;
}
.embla__button {
-webkit-tap-highlight-color: red;
-webkit-appearance: none;
appearance: none;
background-color: transparent;
touch-action: manipulation;
display: inline-flex;
text-decoration: none;
cursor: pointer;
border: 0;
padding: 0;
margin: 0;
box-shadow: inset 0 0 0 0.2rem gray;
width: 3.6rem;
height: 3.6rem;
z-index: 1;
border-radius: 50%;
color: white;
display: flex;
align-items: center;
justify-content: center;
}
.embla__button:disabled {
color: var(--detail-high-contrast);
}
.embla__button__svg {
width: 35%;
height: 35%;
}
.embla__dots {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
align-items: center;
gap: 16px;
margin-right: calc((2.6rem - 1.4rem) / 2 * -1);
}
.embla__dot {
-webkit-tap-highlight-color: rgba(var(--text-high-contrast-rgb-value), 0.5);
-webkit-appearance: none;
appearance: none;
/* background-color: white; */
border: 1px solid white;
touch-action: manipulation;
display: inline-flex;
text-decoration: none;
cursor: pointer;
/* border: 0; */
padding: 0;
margin: 0;
width: 2rem;
height: 2rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.embla__dot:after {
box-shadow: inset 0 0 0 0.2rem var(--detail-medium-contrast);
width: 1.4rem;
height: 1.4rem;
border-radius: 50%;
display: flex;
align-items: center;
content: '';
}
.embla__dot--selected:after {
box-shadow: inset 0 0 0 0.2rem var(--text-body);
}
Loading

0 comments on commit d7e3b94

Please sign in to comment.