Skip to content

Commit

Permalink
Client/feature/mobile version (#76)
Browse files Browse the repository at this point in the history
* Mobile version
  • Loading branch information
barbara-chaves authored Oct 31, 2024
1 parent d7e3b94 commit 8dfb783
Show file tree
Hide file tree
Showing 19 changed files with 218 additions and 155 deletions.
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
14 changes: 9 additions & 5 deletions client/src/components/map/layers/marker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
'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';
import { useBreakpoint } from '@/hooks/screen-size';
import { XIcon } from 'lucide-react';

type MarkerProps = {
markers?: (GeoJSON.Feature<GeoJSON.Point> | null)[];
Expand All @@ -16,7 +20,7 @@ type MarkerProps = {
const Marker = ({ markers, handleClick, handleClose }: MarkerProps) => {
const { coordinates } = markers?.[0]?.geometry || {};

const isMobile = !useBreakpoint()('sm');
const isMobile = useIsMobile();

if (!coordinates?.length) return null;

Expand Down Expand Up @@ -55,9 +59,9 @@ const Marker = ({ markers, handleClick, handleClose }: MarkerProps) => {
/>
<p className="font-open-sans text-xs">{marker?.properties?.categoryName}</p>
<Button
className="absolute right-0 top-0"
className="absolute right-0 top-0 sm:hidden"
size="icon"
variant="ghost"
variant="icon"
onClick={handleClose}
>
<XIcon className="h-5 w-5" />
Expand Down
7 changes: 4 additions & 3 deletions client/src/components/map/legend/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use client';

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

import { ChevronDown } from 'lucide-react';

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

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

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

Expand All @@ -15,8 +17,7 @@ export const Legend: React.FC<LegendProps> = ({ children, className = '' }: Lege
return !!Children.count(Children.toArray(children).filter((c) => isValidElement(c)));
}, [children]);

const breakpoint = useBreakpoint();
const isMobile = !breakpoint('sm');
const isMobile = useIsMobile();

return (
isChildren && (
Expand Down
6 changes: 4 additions & 2 deletions client/src/components/ui/carousel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import React, {
useState,
} from 'react';

import Image from 'next/image';

import { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel';
import useEmblaCarousel from 'embla-carousel-react';
import Image from 'next/image';
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';

import { cn } from '@/lib/classnames';
import { getImageSrc } from '@/lib/image-src';
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';

type UseDotButtonType = {
selectedIndex: number;
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/ui/scroll-explanation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const ScrollExplanation = ({ children }: PropsWithChildren) => {
return (
<div className="font-notes z-10 flex w-full items-center justify-center gap-2 text-center text-sm italic text-white">
<div className="flex h-8 w-4 justify-center rounded-full border border-gray-200 bg-gray-900">
<div className="animate-fade-down h-2 w-2 rounded-full bg-gray-200" />
<div className="animate-fade-up sm:animate-fade-down h-2 w-2 rounded-full bg-gray-200" />
</div>
<p>{children}</p>
</div>
Expand Down
3 changes: 2 additions & 1 deletion client/src/containers/globe/categories/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { cn } from '@/lib/classnames';

import { useGetCategories } from '@/types/generated/category';

import ContentLoader from '@/components/ui/loader';
import { Skeleton } from '@/components/ui/skeleton';

import Category from './item';
import { cn } from '@/lib/classnames';

type CategoriesProps = {
className?: string;
Expand Down
22 changes: 13 additions & 9 deletions client/src/containers/globe/filters/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import { useMemo } from 'react';

import {
Expand All @@ -8,21 +10,24 @@ import {
DialogPortal,
DialogOverlay,
} from '@radix-ui/react-dialog';
import { RadioGroup, RadioGroupItem } from '@radix-ui/react-radio-group';
import { FilterIcon, XIcon } from 'lucide-react';

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

import { useSyncCategory } from '@/store/globe';

import { useGetCategories } from '@/types/generated/category';
import { useGetIfis } from '@/types/generated/ifi';
import { useGetTags } from '@/types/generated/tag';

import FilterItem from './item';
import { useGetCategories } from '@/types/generated/category';
import { useSyncCategory } from '@/store/globe';
import { RadioGroup, RadioGroupItem } from '@radix-ui/react-radio-group';
import { useBreakpoint } from '@/hooks/screen-size';
import { ScrollArea } from '@/components/ui/scroll-area';
import { DialogHeader } from '@/components/ui/dialog';
import { useIsMobile } from '@/hooks/screen-size';

import { Button } from '@/components/ui/button';
import { DialogHeader } from '@/components/ui/dialog';
import { ScrollArea } from '@/components/ui/scroll-area';

import FilterItem from './item';

type FiltersProps = {
filtersActive: boolean;
Expand All @@ -33,8 +38,7 @@ const Filters = ({ filtersActive }: FiltersProps) => {
const { data: ifisData } = useGetIfis({ 'pagination[limit]': 1000 });
const { data: categoriesData } = useGetCategories();

const breakpoint = useBreakpoint();
const isMobile = !breakpoint('sm');
const isMobile = useIsMobile();
const filtersData = useMemo(() => {
return [
{
Expand Down
12 changes: 8 additions & 4 deletions client/src/containers/globe/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { useEffect } from 'react';
import { motion } from 'framer-motion';

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

import { useSetAtom } from 'jotai';
Expand All @@ -14,7 +14,8 @@ import { useSyncFilters } from '@/store/globe';
import { layersAtom, tmpBboxAtom } from '@/store/map';
import { useSyncStep } from '@/store/stories';

import { useBreakpoint } from '@/hooks/screen-size';
import { setMapEnable } from '@/hooks/map';
import { useIsMobile } from '@/hooks/screen-size';
import useStories from '@/hooks/stories/useStories';

import { DEFAULT_MOBILE_ZOOM, DEFAULT_VIEW_STATE } from '@/components/map/constants';
Expand Down Expand Up @@ -47,8 +48,7 @@ export default function Home() {
const storiesLength = storiesData?.data?.length;
const { default: map } = useMap();

const breakpoint = useBreakpoint();
const isMobile = !breakpoint('sm');
const isMobile = useIsMobile();

useEffect(() => {
const bounds = new mapboxgl.LngLatBounds();
Expand All @@ -74,6 +74,10 @@ export default function Home() {
zoom: isMobile ? DEFAULT_MOBILE_ZOOM : DEFAULT_VIEW_STATE.zoom,
},
});

const MAP = map?.getMap();
setMapEnable(MAP, true);
map?.resize();
}, [isMobile, map, setTmpBbox, storiesData?.data]);

useEffect(() => {
Expand Down
11 changes: 6 additions & 5 deletions client/src/containers/header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Header = ({ pathname, className }: HeaderProps) => {
return (
<header className={cn('pointer-events-auto z-50', className)}>
<div className="flex items-center justify-between space-x-1.5 px-4 py-4 sm:px-0">
<div className="flex flex-1 items-center space-x-3">
<div className={cn('flex items-center space-x-3', !isHome && 'flex-1')}>
<div className="flex shrink-0 items-center space-x-3">
<a href="https://gda.esa.int/" target="_blank" rel="noreferrer">
<Image
Expand All @@ -36,14 +36,15 @@ const Header = ({ pathname, className }: HeaderProps) => {
/>
</a>
</div>
<GradientLine className={cn('flex-1', isHome && 'hidden sm:block')} />
<GradientLine className={cn('flex-1', isHome && 'hidden')} />
</div>

<div className={cn('py-2 sm:px-4', isHome && 'hidden sm:flex')}>
<h1 className="text-xs font-bold uppercase tracking-[2.4px] sm:text-base sm:font-normal sm:tracking-[6.4px]">
<div className={cn('py-2 sm:px-4', isHome && 'hidden')}>
<p className="text-xs font-bold uppercase tracking-[2.4px] sm:text-base sm:font-normal sm:tracking-[6.4px]">
<Link href="/home">Impact Sphere</Link>
</h1>
</p>
</div>

<div className={cn('flex flex-1 items-center space-x-3', !isHome && 'hidden sm:flex')}>
<GradientLine className={cn('flex-1')} />
<div className="text-sm font-bold uppercase tracking-widest">
Expand Down
55 changes: 9 additions & 46 deletions client/src/containers/home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
'use client';

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

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

import Link from 'next/link';
import { useRouter } from 'next/navigation';

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

import { homeMarkerAtom } from '@/store/home';

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

import { DEFAULT_MOBILE_ZOOM } from '@/components/map/constants';
import { Dialog, DialogContentHome } from '@/components/ui/dialog';
Expand All @@ -34,11 +33,8 @@ const Home = () => {
width: 1,
height: 1,
});
const breakpoint = useBreakpoint();
const isMobile = !breakpoint('sm');
const isLg = breakpoint('xl');

const [paddingTop, setPaddingTop] = useState(0);
const isMobile = useIsMobile();

const spin = useCallback(() => {
if (!map) return;
Expand All @@ -56,16 +52,17 @@ const Home = () => {
padding: {
left: !isMobile ? size.width * 0.45 : 0,
right: 0,
top: isMobile ? paddingTop : 0,
bottom: isLg || isMobile ? 0 : size.height * 0.5,
top: 0,
bottom: 0,
},
easing: (n) => n,
});
}, [isLg, isMobile, map, paddingTop, size.height, size.width]);
}, [isMobile, map, size.width]);

useEffect(() => {
if (map) {
spin();
map.resize();
map.on('moveend', spin);
return () => {
map.stop();
Expand All @@ -81,7 +78,6 @@ const Home = () => {
const w = window?.innerWidth || 1;
const h = window?.innerHeight || 1;
setSize({ width: w, height: h });
setPaddingTop(h * 1);
};

if (typeof window !== 'undefined') {
Expand All @@ -104,42 +100,9 @@ const Home = () => {
visible: { opacity: 1 },
};

const [firstRender, setFirstRender] = useState(true);

useEffect(() => {
// Scroll to top on first render
if (typeof window !== 'undefined') {
window.scroll({ top: 0 });
}
// Prevent pushing to globe before scrolling top on first render
setFirstRender(false);
}, []);

const containerRef = useRef<HTMLDivElement>(null);

const { scrollYProgress } = useScroll({
target: containerRef,
axis: 'y',
offset: ['start start', 'end end'],
layoutEffect: false,
});

const router = useRouter();
useMotionValueEvent(scrollYProgress, 'change', (v) => {
if (!isMobile || firstRender) return;
setPaddingTop(size.height * (1 - v));

if (v > 0.8) {
router.push('/globe');
}
});

return (
<>
<div
ref={containerRef}
className="text-primary font-notes pointer-events-none absolute flex h-[150vh] min-h-screen w-screen flex-col justify-between sm:h-screen sm:overflow-hidden"
>
<div className="text-primary font-notes pointer-events-none absolute flex h-screen min-h-screen w-screen flex-col justify-between">
<div className="fixed top-0 flex h-screen w-screen flex-col overflow-hidden">
<div className="sm:mx-12">
<Header pathname="home" />
Expand Down
Loading

0 comments on commit 8dfb783

Please sign in to comment.