Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design and content updates #83

Merged
merged 3 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added client/public/images/map/story-marker-lg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/public/images/map/story-marker-sm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed client/public/images/map/story-marker.png
Binary file not shown.
10 changes: 8 additions & 2 deletions client/src/components/chart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,15 @@ const ChartJs = ({ widget, ...props }: ChartJsProps) => {
};

return (
<div {...props}>
<div className="w-full">
{!chartTypes.includes(chartType) || !data || !(data as ChartData).datasets ? null : (
<Chart ref={chartRef} type={chartType} options={OPTIONS} data={dataWithDefaults} />
<Chart
{...props}
ref={chartRef}
type={chartType}
options={OPTIONS}
data={dataWithDefaults}
/>
)}
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/map/layers/marker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const Marker = ({ markers, handleClick, handleClose }: MarkerProps) => {
>
<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':
'absolute left-1/2 top-1/2 flex h-4 w-4 -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,
})}
Expand Down
24 changes: 5 additions & 19 deletions client/src/components/ui/carousel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import React, {
PropsWithChildren,
useCallback,
useEffect,
useRef,
useState,
} from 'react';

Expand Down Expand Up @@ -149,30 +148,18 @@ type CarouselMediaProps = {
};

export const CarouselMedia = ({ media, isCurrentMedia }: CarouselMediaProps) => {
const videoRef = useRef<HTMLVideoElement>(null);
const mediaSrc = getImageSrc(media?.url);

useEffect(() => {
if (!isCurrentMedia && videoRef.current) {
videoRef.current?.pause();
} else if (isCurrentMedia && videoRef.current) {
videoRef.current?.play();
}
}, [isCurrentMedia]);

if (media?.type === 'video') {
return (
<video
ref={videoRef}
width="100%"
height="100%"
src={mediaSrc}
muted={!isCurrentMedia}
loop
controls={isCurrentMedia}
autoPlay={isCurrentMedia}
controls
className={cn(
'h-full max-h-[calc(100vh-152px)] w-full',
'h-full max-h-[calc(100vh-152px)] w-full bg-black',
isCurrentMedia ? 'object-contain' : 'object-cover'
)}
>
Expand Down Expand Up @@ -228,15 +215,14 @@ const EmblaCarousel: React.FC<PropType> = ({ options, medias, selected }) => {
<div className="embla__viewport w-full" ref={emblaRef}>
<div
className={cn(
'embla__container items-center',
medias?.length > 1 ? '-ml-4 sm:-ml-6' : ''
'embla__container -ml-4 items-center sm:-ml-10',
medias.length === 1 && ' justify-center'
)}
>
{medias?.map((media, index) => (
<div
className={cn(
'embla__slide',
medias?.length > 1 ? 'flex-[0_0_80%] pl-4 sm:pl-6' : 'flex-1',
'embla__slide flex-[0_0_60%] pl-4 sm:pl-10',
index === currSlider ? 'h-[80vh]' : 'h-[40vh]'
)}
key={index}
Expand Down
6 changes: 3 additions & 3 deletions client/src/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay
ref={ref}
className={cn(
'bg-background/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 backdrop-blur-sm',
'bg-background/40 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 backdrop-blur-[2px]',
className
)}
{...props}
Expand All @@ -46,8 +46,8 @@ const DialogContent = React.forwardRef<
{...props}
>
{children}
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-8 rounded-full bg-white p-1 opacity-70 backdrop-blur-lg transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none sm:p-1">
<X className="h-6 w-6" />
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-8 flex w-14 justify-center rounded-full border border-gray-800 bg-gray-900 p-1 opacity-70 backdrop-blur-lg transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none sm:p-1">
<X className="h-6 w-6 text-white" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
Expand Down
7 changes: 6 additions & 1 deletion client/src/components/ui/rich-text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ const RichText = ({ children, className }: RichTextProps) => {
{props.children}
</ol>
),
li: ({ node, ...props }) => (
<li {...props} className="ml-4 list-disc">
{props.children}
</li>
),
img: ({ node, ...props }) => (
<Image
{...props}
Expand All @@ -42,7 +47,7 @@ const RichText = ({ children, className }: RichTextProps) => {
),
video: ({ node, ...props }) => {
return (
<video {...props} controls className="h-auto w-full">
<video {...props} controls className="h-auto min-h-[418px] w-full">
<source src={props.src} />
</video>
);
Expand Down
4 changes: 2 additions & 2 deletions client/src/containers/globe/dashboard/numbers.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const numbers = [
{ stat: 'Supported countries', number: 53 },
{ stat: 'Supported countries', number: 69 },
{ stat: 'Organizations Involved', number: 41 },
{ stat: 'IFI projects', number: 50 },
{ stat: 'IFI projects', number: 81 },
];

const DashboardNumbers = () => {
Expand Down
6 changes: 4 additions & 2 deletions client/src/containers/globe/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function Home() {
const { removeStep } = useSyncStep();

const { data: storiesData } = useStories();
const storiesLength = storiesData?.data?.length;
const storiesLength = storiesData?.data?.length || 0;
const { default: map } = useMap();

const isMobile = useIsMobile();
Expand Down Expand Up @@ -98,7 +98,9 @@ export default function Home() {
<Filters filtersActive={filtersActive} />
</div>
<div className="font-open-sans flex justify-between text-sm font-semibold">
<p className="pl-1 text-gray-800">{!!storiesLength && `${storiesLength} stories`}</p>
<p className="pl-1 text-gray-800">
{`${storiesLength} featured ${storiesLength === 1 ? 'story' : 'stories'}`}
</p>
<Button
variant="link"
className={cn(
Expand Down
2 changes: 1 addition & 1 deletion client/src/containers/home/satellite-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const SatelliteButton = ({ handleSelectMarker, satellite, className }: Satellite
return (
<button
className={cn(
'pointer-events-auto absolute z-50 flex cursor-pointer items-center justify-center',
'pointer-events-auto absolute z-50 flex cursor-pointer items-center justify-center transition-all duration-300 hover:scale-110',
className
)}
onClick={() => handleSelectMarker(satellite.id)}
Expand Down
15 changes: 9 additions & 6 deletions client/src/containers/map/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';

import { MapLayerMouseEvent, useMap } from 'react-map-gl';

import dynamic from 'next/dynamic';
import { usePathname, useRouter } from 'next/navigation';
import { usePathname } from 'next/navigation';

import { useMotionValueEvent, useScroll } from 'framer-motion';
import { useAtomValue, useSetAtom } from 'jotai';
import { LngLatBoundsLike } from 'mapbox-gl';

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

import { bboxAtom, layersInteractiveIdsAtom, mapScrollAtom, tmpBboxAtom } from '@/store/map';
import { bboxAtom, layersInteractiveIdsAtom, tmpBboxAtom } from '@/store/map';

import { Bbox } from '@/types/map';

Expand Down Expand Up @@ -148,8 +147,12 @@ export default function MapContainer() {
)}
>
<LayerManager />
<GlobeMarkers />
<SelectedStoriesMarker markers={markers} onCloseMarker={() => setMarkers([])} />
{!isStoriesPage && (
<>
<GlobeMarkers />
<SelectedStoriesMarker markers={markers} onCloseMarker={() => setMarkers([])} />
</>
)}
{isStoriesPage && <StoryMarkers />}
</Map>
</div>
Expand Down
57 changes: 54 additions & 3 deletions client/src/containers/map/markers/globe-markers/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useMemo } from 'react';
import { useEffect, useMemo, useState } from 'react';

import { Layer, Source } from 'react-map-gl';

Expand Down Expand Up @@ -41,7 +41,12 @@ const GlobeMarkers = () => {

useMapImage({
name: 'story-marker',
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/map/story-marker.png`,
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/map/story-marker-sm.png`,
});

useMapImage({
name: 'story-marker-lg',
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/map/story-marker-lg.png`,
});

const pathname = usePathname();
Expand All @@ -50,7 +55,35 @@ const GlobeMarkers = () => {
[pathname]
);

return (
const [size, setSize] = useState(1);

const [opacity, setOpacity] = useState(1);

// Animate the size and opacity of the markers
useEffect(() => {
if (typeof window === 'undefined') return;
const startTime = performance.now();
const velocity = 3000;
const minSize = 0.75;

const animate = () => {
const progress = ((performance.now() - startTime) % velocity) / velocity;
const x = Math.abs(Math.sin(progress * Math.PI));
// Set the opacity interpolating from 0 to 1 and back
setOpacity(x);
const size = x * (1 - minSize) + minSize;
// Set the size interpolating from 0.75 to 1 and back
setSize(size);
requestAnimationFrame(animate);
};

// https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
const frame = requestAnimationFrame(animate);

return () => cancelAnimationFrame(frame);
}, []);

return pathname.includes('stories') ? null : (
<Source id="story-markers" type="geojson" data={FeatureCollection}>
<Layer
id="story-markers-cluster"
Expand Down Expand Up @@ -81,17 +114,35 @@ const GlobeMarkers = () => {
}}
/>

<Layer
id="story-markers-unclustered-lg"
type="symbol"
filter={['!', ['has', 'point_count']]}
paint={{
'icon-color': '#FFE094',
}}
layout={{
'icon-image': 'story-marker-lg',
'icon-ignore-placement': true,
'icon-allow-overlap': true,
'icon-size': size,
visibility,
}}
/>
<Layer
id="story-markers-unclustered"
type="symbol"
filter={['!', ['has', 'point_count']]}
paint={{
'icon-color': '#FFE094',
'icon-opacity': 1 - opacity,
}}
layout={{
'icon-image': 'story-marker',
'icon-ignore-placement': true,
'icon-allow-overlap': true,
'icon-size': 1,
'icon-offset': [0.75, 1.75],
visibility,
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ const MapContent = ({ showContent, title, titlePlaceholder, children }: MapConte
<Collapsible
defaultOpen
className={cn(
'group pointer-events-auto w-full overflow-hidden rounded border-gray-800 p-2 transition-all duration-300 ease-in-out sm:border sm:bg-[#335e6f]/80 sm:backdrop-blur',
'group pointer-events-auto w-full overflow-hidden rounded border-gray-800 p-2 transition-all duration-300 ease-in-out sm:border sm:bg-[rgba(51,94,111,0.8)] sm:backdrop-blur',
showContent ? 'opacity-100' : 'sm:opacity-0'
)}
>
<CollapsibleTrigger className="group hidden w-full justify-between gap-2 px-4 data-[state=open]:pt-2 sm:flex">
<CollapsibleTrigger className="group pointer-events-none flex w-full justify-between gap-2 px-4 data-[state=open]:pt-2 sm:pointer-events-auto">
<h2 className="font-notes group w-[calc(100%-32px)] flex-1 text-start text-xl font-bold ">
{title ? (
title
Expand All @@ -31,7 +31,7 @@ const MapContent = ({ showContent, title, titlePlaceholder, children }: MapConte
</span>
)}
</h2>
<ChevronDownIcon className="h-6 w-6 shrink-0 group-data-[state=closed]:rotate-180" />
<ChevronDownIcon className="hidden h-6 w-6 shrink-0 group-data-[state=closed]:rotate-180 sm:inline-block" />
</CollapsibleTrigger>
<CollapsibleContent>
<div
Expand Down
Loading
Loading