diff --git a/package.json b/package.json
index 69fddf5..b4de6a9 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"lint": "next lint"
},
"dependencies": {
+ "@artsy/fresnel": "7.1.4",
"@hookform/resolvers": "3.9.0",
"@lukemorales/query-key-factory": "1.3.4",
"@mailchimp/mailchimp_marketing": "3.0.80",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ef49a3b..1eee1f0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,6 +8,9 @@ importers:
.:
dependencies:
+ '@artsy/fresnel':
+ specifier: 7.1.4
+ version: 7.1.4(react@18.3.1)
'@hookform/resolvers':
specifier: 3.9.0
version: 3.9.0(react-hook-form@7.52.1(react@18.3.1))
@@ -197,6 +200,12 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
+ '@artsy/fresnel@7.1.4':
+ resolution: {integrity: sha512-qbUdxzlcI9Q9Ez+HfYDq7hlLoeFKC8EKcCckW+EltWu9SWL3px4QZIkr7NwYEz13q/nLvAlHMnbJ3TpSEEZ1zg==}
+ engines: {node: '>=12.20.2', yarn: 1.x.x}
+ peerDependencies:
+ react: '>=18.0.0'
+
'@babel/code-frame@7.24.7':
resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
engines: {node: '>=6.9.0'}
@@ -4164,6 +4173,10 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
+ '@artsy/fresnel@7.1.4(react@18.3.1)':
+ dependencies:
+ react: 18.3.1
+
'@babel/code-frame@7.24.7':
dependencies:
'@babel/highlight': 7.24.7
diff --git a/public/images/partners/ciencias-ulisboa.webp b/public/images/partners/ciencias-ulisboa.webp
new file mode 100644
index 0000000..3ff0efd
Binary files /dev/null and b/public/images/partners/ciencias-ulisboa.webp differ
diff --git a/public/images/partners/coastwatch.webp b/public/images/partners/coastwatch.webp
new file mode 100644
index 0000000..c1a3ec7
Binary files /dev/null and b/public/images/partners/coastwatch.webp differ
diff --git a/public/images/partners/dreamocracy.webp b/public/images/partners/dreamocracy.webp
new file mode 100644
index 0000000..260dc74
Binary files /dev/null and b/public/images/partners/dreamocracy.webp differ
diff --git a/public/images/partners/ecsa.webp b/public/images/partners/ecsa.webp
new file mode 100644
index 0000000..1db7c6c
Binary files /dev/null and b/public/images/partners/ecsa.webp differ
diff --git a/public/images/partners/forest-world.webp b/public/images/partners/forest-world.webp
new file mode 100644
index 0000000..c083f9f
Binary files /dev/null and b/public/images/partners/forest-world.webp differ
diff --git a/public/images/partners/iaac.webp b/public/images/partners/iaac.webp
new file mode 100644
index 0000000..dee6700
Binary files /dev/null and b/public/images/partners/iaac.webp differ
diff --git a/public/images/partners/necu.webp b/public/images/partners/necu.webp
new file mode 100644
index 0000000..8e08ce4
Binary files /dev/null and b/public/images/partners/necu.webp differ
diff --git a/public/images/partners/nilu.webp b/public/images/partners/nilu.webp
new file mode 100644
index 0000000..806aa7d
Binary files /dev/null and b/public/images/partners/nilu.webp differ
diff --git a/public/images/partners/nioo.webp b/public/images/partners/nioo.webp
new file mode 100644
index 0000000..f73215d
Binary files /dev/null and b/public/images/partners/nioo.webp differ
diff --git a/public/images/partners/niva.webp b/public/images/partners/niva.webp
new file mode 100644
index 0000000..6b72970
Binary files /dev/null and b/public/images/partners/niva.webp differ
diff --git a/public/images/partners/nordeco.webp b/public/images/partners/nordeco.webp
new file mode 100644
index 0000000..fc2ca08
Binary files /dev/null and b/public/images/partners/nordeco.webp differ
diff --git a/public/images/partners/polski-alarm-smogowy.webp b/public/images/partners/polski-alarm-smogowy.webp
new file mode 100644
index 0000000..d776671
Binary files /dev/null and b/public/images/partners/polski-alarm-smogowy.webp differ
diff --git a/public/images/partners/rivm.webp b/public/images/partners/rivm.webp
new file mode 100644
index 0000000..595f7b0
Binary files /dev/null and b/public/images/partners/rivm.webp differ
diff --git a/public/images/partners/tracasa.webp b/public/images/partners/tracasa.webp
new file mode 100644
index 0000000..17327a7
Binary files /dev/null and b/public/images/partners/tracasa.webp differ
diff --git a/public/images/partners/un-wcmc.webp b/public/images/partners/un-wcmc.webp
new file mode 100644
index 0000000..9ec696b
Binary files /dev/null and b/public/images/partners/un-wcmc.webp differ
diff --git a/public/images/partners/university-copenhagen.webp b/public/images/partners/university-copenhagen.webp
new file mode 100644
index 0000000..8c38359
Binary files /dev/null and b/public/images/partners/university-copenhagen.webp differ
diff --git a/public/images/partners/vito.webp b/public/images/partners/vito.webp
new file mode 100644
index 0000000..0df52de
Binary files /dev/null and b/public/images/partners/vito.webp differ
diff --git a/public/images/partners/vizzuality.webp b/public/images/partners/vizzuality.webp
new file mode 100644
index 0000000..1a94fd8
Binary files /dev/null and b/public/images/partners/vizzuality.webp differ
diff --git a/src/app/cases/[id]/page.tsx b/src/app/cases/[id]/page.tsx
index 756465b..1684b72 100644
--- a/src/app/cases/[id]/page.tsx
+++ b/src/app/cases/[id]/page.tsx
@@ -5,9 +5,8 @@ import queryKeys from '@/lib/query-keys';
import CASE_STUDIES from '@/data/case-studies';
-import CaseDetailSidebar from '@/containers/case-detail/sidebar';
-import Map from '@/containers/cases/map';
-import Sidebar from '@/containers/cases/sidebar';
+import ResponsiveCaseDetailPage from '@/app/cases/[id]/responsive';
+
import { INITIAL_FILTERS_STATE } from '@/containers/cases/store';
const prefetchData = async (queryClient: QueryClient, id: string) => {
@@ -32,10 +31,7 @@ export default async function CaseDetail({ params: { id } }: { params: { id: str
return (
-
-
-
-
+
);
}
diff --git a/src/app/cases/[id]/responsive.tsx b/src/app/cases/[id]/responsive.tsx
new file mode 100644
index 0000000..c90fb55
--- /dev/null
+++ b/src/app/cases/[id]/responsive.tsx
@@ -0,0 +1,24 @@
+'use client';
+
+import CaseDetailSidebar from '@/containers/case-detail/sidebar';
+import CasesMap from '@/containers/cases/map';
+import Sidebar from '@/containers/cases/sidebar';
+import { Media } from '@/containers/media';
+
+export default function ResponsiveCaseDetailPage() {
+ return (
+ <>
+
+
+
+
+ <>
+
+
+
+
+ >
+
+ >
+ );
+}
diff --git a/src/app/cases/page.tsx b/src/app/cases/page.tsx
index 17527e8..70d4776 100644
--- a/src/app/cases/page.tsx
+++ b/src/app/cases/page.tsx
@@ -5,13 +5,9 @@ import queryKeys from '@/lib/query-keys';
import CASE_STUDIES from '@/data/case-studies';
-import CaseStudies from '@/containers/cases';
-import Map from '@/containers/cases/map';
-import Sidebar from '@/containers/cases/sidebar';
-import { INITIAL_FILTERS_STATE } from '@/containers/cases/store';
-import CaseStudiesTotal from '@/containers/cases/total';
+import ResponsiveCasesPage from '@/app/cases/responsive';
-import { ScrollArea } from '@/components/ui/scroll-area';
+import { INITIAL_FILTERS_STATE } from '@/containers/cases/store';
const prefetchData = async (queryClient: QueryClient) => {
const caseStudiesService = new CaseStudyService(CASE_STUDIES, {}, {});
@@ -29,17 +25,7 @@ export default async function Cases() {
return (
-
-
-
-
-
-
-
-
-
-
-
+
);
}
diff --git a/src/app/cases/responsive.tsx b/src/app/cases/responsive.tsx
new file mode 100644
index 0000000..46b6fe0
--- /dev/null
+++ b/src/app/cases/responsive.tsx
@@ -0,0 +1,85 @@
+'use client';
+
+import { useRef, useState } from 'react';
+
+import { motion, useInView } from 'framer-motion';
+
+import CaseStudies from '@/containers/cases';
+import FiltersContent from '@/containers/cases/header/filters/filters-dropdown/content';
+import MobileFiltersDropdown from '@/containers/cases/header/filters/filters-dropdown/mobile';
+import CasesMap from '@/containers/cases/map';
+import Sidebar from '@/containers/cases/sidebar';
+import CaseStudiesTotal from '@/containers/cases/total';
+import { Media } from '@/containers/media';
+
+import { ScrollArea } from '@/components/ui/scroll-area';
+
+export default function ResponsiveCasesPage() {
+ const ref = useRef(null);
+ const inView = useInView(ref, { amount: 0.15 });
+ const [isFiltersOpen, setIsFiltersOpen] = useState(false);
+
+ const handleOpenFilters = () => {
+ setIsFiltersOpen((prev) => !prev);
+ };
+
+ const closeFilters = () => {
+ setIsFiltersOpen(false);
+ };
+
+ return (
+ <>
+
+
+
+ {}} onClickFilters={handleOpenFilters} />
+
+
+
+
+ {}} onClickFilters={handleOpenFilters} />
+
+
+
+
+
+
+
+
+
+
+
+
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+
+ >
+ );
+}
diff --git a/src/app/head.tsx b/src/app/head.tsx
new file mode 100644
index 0000000..68abf90
--- /dev/null
+++ b/src/app/head.tsx
@@ -0,0 +1,13 @@
+'use client';
+
+import { mediaStyles } from '@/containers/media';
+
+function RootHead() {
+ return (
+
+
+
+ );
+}
+
+export default RootHead;
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index e2c665b..b3f4436 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -5,6 +5,7 @@ import { Lexend } from 'next/font/google';
import type { Metadata } from 'next';
import './globals.css';
+import RootHead from '@/app/head';
import LayoutProviders from '@/app/providers';
const lexend = Lexend({ subsets: ['latin'], weight: ['100', '400', '500', '700'] });
@@ -51,6 +52,7 @@ export default function RootLayout({ children }: Readonly) {
return (
+
{children}
diff --git a/src/app/providers.tsx b/src/app/providers.tsx
index 9f276f4..ad893bf 100644
--- a/src/app/providers.tsx
+++ b/src/app/providers.tsx
@@ -4,6 +4,8 @@ import { PropsWithChildren } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { MediaContextProvider } from '@/containers/media';
+
function makeQueryClient() {
return new QueryClient({
defaultOptions: {
@@ -39,7 +41,9 @@ export default function LayoutProviders({ children }: PropsWithChildren) {
return (
<>
- {children}
+
+ {children}
+
>
);
}
diff --git a/src/components/animated-menu/index.tsx b/src/components/animated-menu/index.tsx
new file mode 100644
index 0000000..384a961
--- /dev/null
+++ b/src/components/animated-menu/index.tsx
@@ -0,0 +1,59 @@
+import { useRef, useEffect } from 'react';
+
+import { useCycle, motion } from 'framer-motion';
+
+import { MenuToggle } from '@/components/animated-menu/toggle';
+
+export const useDimensions = (ref) => {
+ const dimensions = useRef({ width: 0, height: 0 });
+
+ useEffect(() => {
+ dimensions.current.width = ref.current.offsetWidth;
+ dimensions.current.height = ref.current.offsetHeight;
+ }, [ref]);
+
+ return dimensions.current;
+};
+
+const sidebar = {
+ open: (height = 1000) => ({
+ clipPath: `circle(${height * 2 + 200}px at 710px 42px)`,
+ transition: {
+ type: 'spring',
+ stiffness: 20,
+ restDelta: 2,
+ },
+ }),
+ closed: {
+ clipPath: 'circle(30px at 710px 42px)',
+ transition: {
+ // delay: 0.5,
+ type: 'spring',
+ stiffness: 400,
+ damping: 40,
+ },
+ },
+};
+
+export default function AnimatedMenu() {
+ const [isOpen, toggleOpen] = useCycle(false, true);
+ const containerRef = useRef(null);
+ const { height } = useDimensions(containerRef);
+
+ return (
+
+
+ {/**/}
+ toggleOpen()} />
+
+ );
+}
diff --git a/src/components/animated-menu/toggle.tsx b/src/components/animated-menu/toggle.tsx
new file mode 100644
index 0000000..ca9ed30
--- /dev/null
+++ b/src/components/animated-menu/toggle.tsx
@@ -0,0 +1,40 @@
+import * as React from 'react';
+
+import { motion } from 'framer-motion';
+
+const Path = (props) => (
+
+);
+
+export const MenuToggle = ({ toggle }) => (
+
+);
diff --git a/src/components/app-menu/index.tsx b/src/components/app-menu/index.tsx
index 622533e..53c59a4 100644
--- a/src/components/app-menu/index.tsx
+++ b/src/components/app-menu/index.tsx
@@ -6,6 +6,7 @@ import { motion } from 'framer-motion';
import { HiOutlineMenuAlt4 } from 'react-icons/hi';
import { SECTIONS } from '@/containers/header';
+import { Media } from '@/containers/media';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
@@ -14,9 +15,11 @@ export default function AppMenu() {
-
- Menu
-
+
+
+ Menu
+
+
-
+
+
+
+
+
+
);
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
index 253ab5b..2a5291b 100644
--- a/src/components/ui/badge.tsx
+++ b/src/components/ui/badge.tsx
@@ -16,6 +16,7 @@ const badgeVariants = cva(
destructive:
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
outline: 'text-foreground',
+ test: 'text-red-400',
},
},
defaultVariants: {
diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx
index 1379016..f2fab46 100644
--- a/src/components/ui/dialog.tsx
+++ b/src/components/ui/dialog.tsx
@@ -39,7 +39,7 @@ const DialogContent = React.forwardRef<
-
-
+
{PARTNERS.map(({ name, description, logo, url }) => (
-
-