Skip to content
Closed
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
20 changes: 10 additions & 10 deletions app/(datasets)/providers.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ReactNode } from 'react';
import DataProvider from 'app/store/providers/data';
import VedaUIConfigProvider from 'app/store/providers/veda-ui-config';
import DevseedUIThemeProvider from 'app/store/providers/theme';
// import DevseedUIThemeProvider from 'app/store/providers/theme';
import { DatasetMetadata } from 'app/types/content';

interface ProviderProps {
Expand All @@ -11,14 +11,14 @@ interface ProviderProps {

export default function Providers({ datasets, children }: ProviderProps) {
return (
<DevseedUIThemeProvider>
<VedaUIConfigProvider>
{datasets ? (
<DataProvider initialDatasets={datasets}>{children}</DataProvider>
) : (
children
)}
</VedaUIConfigProvider>
</DevseedUIThemeProvider>
// <DevseedUIThemeProvider>
<VedaUIConfigProvider>
{datasets ? (
<DataProvider initialDatasets={datasets}>{children}</DataProvider>
) : (
children
)}
</VedaUIConfigProvider>
// </DevseedUIThemeProvider>
);
}
29 changes: 29 additions & 0 deletions app/components/acknowledgements-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Github } from 'lucide-react';
import React from 'react';
import SectionHeader from './section-header';

export default function AcknowledgementsSection() {
return (
<section className='py-16 bg-muted/30'>
<div className='max-w-[1400px] mx-auto px-6 lg:px-12 text-center'>
<SectionHeader
heading='Acknowledgements'
subheading="GRSS VEDA is made possible through a collaboration between the IEEE Geoscience and Remote Sensing Society and NASA's Interagency Implementation and Advanced Concepts Team (IMPACT). GRSS VEDA is deployed and adapted from NASA's open VEDA infrastructure."
overrideHeadingClassName='text-2xl mb-4'
subheadingClassName='text-base mb-6'
/>
<div className='flex flex-wrap gap-4 justify-center items-center'>
<a
href='https://github.com/NASA-IMPACT/veda'
target='_blank'
rel='noopener noreferrer'
className='inline-flex items-center gap-2 text-primary hover:underline focus:outline-2 focus:outline-ring focus:outline-offset-2 rounded'
>
<Github className='h-5 w-5' />
View VEDA on GitHub
</a>
</div>
</div>
</section>
);
}
90 changes: 90 additions & 0 deletions app/components/common/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { InternalNavLink } from '@lib';
import Link from 'next/link';
import React from 'react';

export default function Footer() {
const navItems: InternalNavLink[] = [
{
id: 'home',
title: 'Home',
to: '/',
type: 'internalLink',
},
{
id: 'sitemap',
title: 'Sitemap',
to: '/#',
type: 'internalLink',
},
{
id: 'contact-support',
title: 'Contact & Support',
to: '/#',
type: 'internalLink',
},
{
id: 'accessibility',
title: 'Accessibility',
to: 'https://www.ieee.org/accessibility-statement',
type: 'internalLink',
},
{
id: 'nondiscrimination-policy',
title: 'Nondiscrimination Policy',
to: 'https://www.ieee.org/about/corporate/governance/p9-26',
type: 'internalLink',
},
{
id: 'ethics-reporting',
title: 'IEEE Ethics Reporting',
to: 'https://secure.ethicspoint.com/domain/media/en/gui/20410/index.html',
type: 'internalLink',
},
{
id: 'privacy-policy',
title: 'IEEE Privacy Policy',
to: 'https://privacy.ieee.org/policies',
type: 'internalLink',
},
{
id: 'terms-disclosures',
title: 'Terms & Disclosures',
to: 'https://www.ieee.org/about/help/site-terms-conditions',
type: 'internalLink',
},
{
id: 'feedback',
title: 'Feedback',
to: 'https://www.ieee.org/about/feedback-ieee-site',
type: 'internalLink',
},
];
return (
<footer className='border-t border-border bg-card mt-16'>
<div className='max-w-[1400px] mx-auto px-6 lg:px-12 py-12'>
<div className='flex flex-wrap gap-4 mb-8 text-sm'>
{navItems.map((item, index) => (
<>
<Link
href={item.to}
className='text-muted-foreground hover:text-primary hover:underline focus:outline-2 focus:outline-ring focus:outline-offset-2 rounded'
>
{item.title}
</Link>
{index < navItems.length - 1 && (
<span className='text-muted-foreground'>|</span>
)}
</>
))}
</div>
<div className='space-y-2 text-sm text-muted-foreground'>
<p>
© Copyright 2025 IEEE – All rights reserved. A public charity. IEEE
is the world's largest technical professional organization dedicated
to advancing technology for the benefit of humanity.
</p>
</div>
</div>
</footer>
);
}
179 changes: 179 additions & 0 deletions app/components/common/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
'use client';

import { ArrowRight, Menu, Moon, Sun } from 'lucide-react';
import { useState } from 'react';
import { Button } from '../ui/button';
import { Sheet, SheetContent, SheetTrigger } from '../ui/sheet';
import { MetaNavigation } from './meta-navigation';
// import { ImageWithFallback } from './figma/ImageWithFallback';
import { InternalNavLink } from '@lib';
import {
DATASET_CATALOG_PATH,
EXPLORATION_PATH,
STORY_HUB_PATH,
} from 'app/config';
import Link from 'next/link';
import { Separator } from '../ui/separator';
import { useTheme } from './theme-provider';

export default function Header() {
const { theme, setTheme } = useTheme();
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);

const navItems: InternalNavLink[] = [
{
id: 'data-catalog',
title: 'Data Catalog',
to: `/${DATASET_CATALOG_PATH}`,
type: 'internalLink',
},
{
id: 'exploration',
title: 'Exploration',
to: `/${EXPLORATION_PATH}`,
type: 'internalLink',
},
{
id: 'stories',
title: 'Stories',
to: `/${STORY_HUB_PATH}`,
type: 'internalLink',
},
];

return (
<>
<MetaNavigation />
<nav
className='sticky top-[40px] md:top-[100px] lg:top-[40px] z-40 border-b border-border bg-card'
aria-label='Main navigation'
>
<div className='max-w-[1400px] mx-auto px-6 lg:px-12'>
<div className='flex items-center justify-between h-20'>
<div className='flex items-center gap-8'>
<Link
href='/'
className='focus:outline-2 focus:outline-ring focus:outline-offset-2 rounded transition-opacity hover:opacity-80 cursor-pointer'
aria-label='Go to home page'
>
<img
src={
theme === 'dark'
? '/images/GRSS-darkmode-logo.png'
: '/images/GRSS-lightmode-logo.png'
}
alt='GRSS IEEE Logo'
className='h-12'
/>
</Link>
<div className='hidden lg:flex items-center gap-6'>
{navItems.map((item) => (
<Link
key={item.id}
href={item.to}
className='hover:text-primary transition-colors focus:outline-2 focus:outline-ring focus:outline-offset-2 rounded'
>
{item.title}
</Link>
))}
</div>
</div>
<div className='flex items-center gap-3'>
{/* Mobile Menu Button */}
<Sheet open={mobileMenuOpen} onOpenChange={setMobileMenuOpen}>
<SheetTrigger asChild>
<Button
variant='ghost'
size='sm'
className='lg:hidden'
aria-label='Open menu'
>
<Menu className='h-5 w-5' />
</Button>
</SheetTrigger>
<SheetContent side='right' className='w-[300px] sm:w-[400px]'>
<nav className='flex flex-col gap-4 mt-8'>
<a
href='#'
className='text-lg hover:text-primary transition-colors py-2'
onClick={() => setMobileMenuOpen(false)}
>
Data Catalog
</a>
<a
href='#'
className='text-lg hover:text-primary transition-colors py-2'
onClick={() => setMobileMenuOpen(false)}
>
Exploration Tools
</a>
<a
href='#'
className='text-lg hover:text-primary transition-colors py-2'
onClick={() => setMobileMenuOpen(false)}
>
Stories
</a>

<Separator className='my-4' />

<Button
variant='ghost'
className='justify-start text-lg py-6'
onClick={() => {
setMobileMenuOpen(false);
}}
>
About
</Button>

<Button
variant='ghost'
className='justify-start text-lg py-6'
onClick={() => setMobileMenuOpen(false)}
>
Sign-in
</Button>

<Button
className='w-full justify-center'
onClick={() => setMobileMenuOpen(false)}
>
Contact Us
<ArrowRight className='h-4 w-4 ml-2' />
</Button>
</nav>
</SheetContent>
</Sheet>

{/* Desktop Actions */}
<Button
variant='ghost'
size='sm'
aria-label={`Switch to ${theme === 'light' ? 'dark' : 'light'} mode`}
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
className='hidden lg:flex'
>
{theme === 'light' ? (
<Moon className='h-4 w-4' />
) : (
<Sun className='h-4 w-4' />
)}
</Button>
<Button variant='ghost' size='sm' className='hidden lg:flex'>
About
</Button>
<Button variant='ghost' size='sm' className='hidden lg:flex'>
Sign-in
</Button>
<Button size='sm' className='gap-2'>
Contact Us
<ArrowRight className='h-4 w-4' />
</Button>
</div>
</div>
</div>
</nav>
</>
);
}
43 changes: 43 additions & 0 deletions app/components/common/image-with-fallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client';

import React, { useState } from 'react';

const ERROR_IMG_SRC =
'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iODgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuMyIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIzLjciPjxyZWN0IHg9IjE2IiB5PSIxNiIgd2lkdGg9IjU2IiBoZWlnaHQ9IjU2IiByeD0iNiIvPjxwYXRoIGQ9Im0xNiA1OCAxNi0xOCAzMiAzMiIvPjxjaXJjbGUgY3g9IjUzIiBjeT0iMzUiIHI9IjciLz48L3N2Zz4KCg==';

export function ImageWithFallback(
props: React.ImgHTMLAttributes<HTMLImageElement>,
) {
const [didError, setDidError] = useState(false);

const handleError = () => {
setDidError(true);
};

const { src, alt, style, className, ...rest } = props;

return didError ? (
<div
className={`inline-block bg-gray-100 text-center align-middle ${className ?? ''}`}
style={style}
>
<div className='flex items-center justify-center w-full h-full'>
<img
src={ERROR_IMG_SRC}
alt='Error loading image'
{...rest}
data-original-url={src}
/>
</div>
</div>
) : (
<img
src={src}
alt={alt}
className={className}
style={style}
{...rest}
onError={handleError}
/>
);
}
Loading
Loading