Skip to content

Commit 75d1fdc

Browse files
committed
update footer
1 parent f2b493f commit 75d1fdc

2 files changed

Lines changed: 283 additions & 72 deletions

File tree

src/app/components/Footer.tsx

Lines changed: 224 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
'use client';
22
import React from 'react';
3-
import '../styles/Footer.css';
4-
import { Button, IconButton, useTheme } from '@mui/material';
3+
import { Box, IconButton, Typography, useTheme } from '@mui/material';
54
import { GitHub, LinkedIn, OpenInNew } from '@mui/icons-material';
65
import { MOBILITY_DATA_LINKS } from '../constants/Navigation';
76
import { fontFamily } from '../Theme';
7+
import Image from 'next/image';
8+
import { useTranslations } from 'next-intl';
9+
import { FooterLink, FooterColumnTitle } from './FooterElements';
810

911
const Footer: React.FC = () => {
10-
// TODO: revisit theming for SSR components
1112
const theme = useTheme();
13+
const t = useTranslations('footer');
14+
const FooterColumnWidth = '185px';
1215
const SlackSvg = (
1316
<svg
1417
xmlns='http://www.w3.org/2000/svg'
@@ -17,86 +20,235 @@ const Footer: React.FC = () => {
1720
viewBox='0 0 24 24'
1821
>
1922
<path
20-
fill={theme.palette.primary.main}
23+
fill='currentColor'
2124
d='M6 15a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2h2zm1 0a2 2 0 0 1 2-2a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2a2 2 0 0 1-2-2zm2-8a2 2 0 0 1-2-2a2 2 0 0 1 2-2a2 2 0 0 1 2 2v2zm0 1a2 2 0 0 1 2 2a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2a2 2 0 0 1 2-2zm8 2a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2h-2zm-1 0a2 2 0 0 1-2 2a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2a2 2 0 0 1 2 2zm-2 8a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2v-2zm0-1a2 2 0 0 1-2-2a2 2 0 0 1 2-2h5a2 2 0 0 1 2 2a2 2 0 0 1-2 2z'
2225
/>
2326
</svg>
2427
);
2528

29+
const currentYear = new Date().getFullYear();
30+
2631
return (
27-
<footer className='footer' style={{ fontFamily: fontFamily.secondary }}>
28-
<a
29-
href={'https://share.mobilitydata.org/mobility-database-feedback'}
30-
target={'_blank'}
31-
rel='noreferrer'
32-
className={'btn-link'}
32+
<Box
33+
component='footer'
34+
sx={{
35+
backgroundColor: theme.palette.background.paper,
36+
width: '100%',
37+
boxSizing: 'border-box',
38+
mt: 6,
39+
}}
40+
>
41+
{/* Main footer content */}
42+
<Box
43+
sx={{
44+
display: 'flex',
45+
flexDirection: { xs: 'column', md: 'row' },
46+
gap: { xs: 4, md: 2 },
47+
px: { xs: 3, md: 8 },
48+
py: 5,
49+
maxWidth: '1400px',
50+
mx: 'auto',
51+
flexWrap: 'wrap',
52+
}}
3353
>
34-
<Button
54+
{/* Brand column */}
55+
<Box sx={{ flex: 2, minWidth: '200px', pr: { md: 4 } }}>
56+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
57+
<Image
58+
src={
59+
theme.palette.mode === 'light'
60+
? '/assets/MOBILTYDATA_logo_light_blue_M.png'
61+
: '/assets/MOBILTYDATA_logo_purple_M.png'
62+
}
63+
alt={t('aria.logo')}
64+
width={32}
65+
height={32}
66+
/>
67+
<Typography
68+
variant='h6'
69+
sx={{
70+
fontWeight: 700,
71+
}}
72+
>
73+
MobilityDatabase
74+
</Typography>
75+
</Box>
76+
77+
<Typography
78+
sx={{
79+
color: theme.palette.text.secondary,
80+
fontSize: theme.typography.body2.fontSize,
81+
lineHeight: 1.6,
82+
mb: 3,
83+
fontFamily: fontFamily.primary,
84+
}}
85+
>
86+
{t('tagline')}
87+
</Typography>
88+
89+
<Box sx={{ display: 'flex', gap: 0.5 }}>
90+
<IconButton
91+
aria-label={t('aria.github')}
92+
component='a'
93+
href={MOBILITY_DATA_LINKS.github}
94+
target='_blank'
95+
rel='noreferrer'
96+
size='small'
97+
>
98+
<GitHub />
99+
</IconButton>
100+
<IconButton
101+
aria-label={t('aria.slack')}
102+
component='a'
103+
href={MOBILITY_DATA_LINKS.slack}
104+
target='_blank'
105+
rel='noreferrer'
106+
size='small'
107+
>
108+
{SlackSvg}
109+
</IconButton>
110+
<IconButton
111+
aria-label={t('aria.linkedin')}
112+
component='a'
113+
href={MOBILITY_DATA_LINKS.linkedin}
114+
target='_blank'
115+
rel='noreferrer'
116+
size='small'
117+
>
118+
<LinkedIn />
119+
</IconButton>
120+
</Box>
121+
</Box>
122+
123+
<Box
35124
sx={{
36-
textTransform: 'none',
37-
mb: 2,
38-
fontFamily: fontFamily.secondary,
125+
width: '100%',
126+
display: 'flex',
127+
gap: 1,
128+
flexWrap: 'wrap',
129+
maxWidth: '800px',
39130
}}
40-
variant={'outlined'}
41-
endIcon={<OpenInNew />}
42-
>
43-
Help Us by Sharing Feedback
44-
</Button>
45-
</a>
46-
<div style={{ margin: 0, display: 'flex', justifyContent: 'center' }}>
47-
<IconButton
48-
aria-label='slack'
49-
className='link-button'
50-
color='primary'
51-
component='a'
52-
href={MOBILITY_DATA_LINKS.slack}
53-
target='_blank'
54-
rel='noreferrer'
55-
>
56-
{SlackSvg}
57-
</IconButton>
58-
<IconButton
59-
aria-label='linkedin'
60-
className='link-button'
61-
color='primary'
62-
component='a'
63-
href={MOBILITY_DATA_LINKS.linkedin}
64-
target='_blank'
65-
rel='noreferrer'
66-
>
67-
<LinkedIn />
68-
</IconButton>
69-
<IconButton
70-
aria-label='github'
71-
className='link-button'
72-
color='primary'
73-
component='a'
74-
href={MOBILITY_DATA_LINKS.github}
75-
target='_blank'
76-
rel='noreferrer'
77131
>
78-
<GitHub />
79-
</IconButton>
80-
</div>
81-
<p style={{ margin: 0 }}>Maintained with &#128156; by MobilityData.</p>
82-
<Button
83-
variant='text'
84-
href={'/privacy-policy'}
85-
target={'_blank'}
86-
rel={'noreferrer'}
87-
>
88-
Privacy Policy
89-
</Button>
90-
|
91-
<Button
92-
variant='text'
93-
href={'/terms-and-conditions'}
94-
target={'_blank'}
95-
rel={'noreferrer'}
132+
{/* Platform column */}
133+
<Box sx={{ width: FooterColumnWidth }}>
134+
<FooterColumnTitle>{t('columns.platform')}</FooterColumnTitle>
135+
<FooterLink href='/feeds'>{t('links.feeds')}</FooterLink>
136+
<FooterLink href='/contribute'>{t('links.addFeed')}</FooterLink>
137+
<FooterLink
138+
href='https://mobilitydata.github.io/mobility-feed-api/SwaggerUI/index.html'
139+
external
140+
>
141+
{t('links.apiDocs')}
142+
</FooterLink>
143+
</Box>
144+
145+
{/* Validators column */}
146+
<Box sx={{ width: FooterColumnWidth }}>
147+
<FooterColumnTitle>{t('columns.validators')}</FooterColumnTitle>
148+
<FooterLink
149+
href='https://gtfs-validator.mobilitydata.org/'
150+
external
151+
>
152+
{t('links.gtfsValidator')}{' '}
153+
<OpenInNew sx={{ fontSize: '1rem', verticalAlign: 'middle' }} />
154+
</FooterLink>
155+
<FooterLink
156+
href='https://github.com/MobilityData/gtfs-realtime-validator'
157+
external
158+
>
159+
{t('links.gtfsRtValidator')}{' '}
160+
<OpenInNew sx={{ fontSize: '1rem', verticalAlign: 'middle' }} />
161+
</FooterLink>
162+
<FooterLink
163+
href='https://gbfs-validator.mobilitydata.org/'
164+
external
165+
>
166+
{t('links.gbfsValidator')}{' '}
167+
<OpenInNew sx={{ fontSize: '1rem', verticalAlign: 'middle' }} />
168+
</FooterLink>
169+
</Box>
170+
171+
{/* Company column */}
172+
<Box sx={{ width: FooterColumnWidth }}>
173+
<FooterColumnTitle>{t('columns.company')}</FooterColumnTitle>
174+
<FooterLink href='/about'>{t('links.about')}</FooterLink>
175+
<FooterLink href='/faq'>{t('links.faq')}</FooterLink>
176+
<FooterLink href='/contact-us'>{t('links.contactUs')}</FooterLink>
177+
<FooterLink
178+
href='https://share.mobilitydata.org/mobility-database-feedback'
179+
external
180+
>
181+
{t('links.shareFeedback')}
182+
</FooterLink>
183+
</Box>
184+
185+
{/* Legal column */}
186+
<Box sx={{ width: FooterColumnWidth }}>
187+
<FooterColumnTitle>{t('columns.legal')}</FooterColumnTitle>
188+
<FooterLink href='/privacy-policy'>
189+
{t('links.privacyPolicy')}
190+
</FooterLink>
191+
<FooterLink href='/terms-and-conditions'>
192+
{t('links.termsAndConditions')}
193+
</FooterLink>
194+
</Box>
195+
</Box>
196+
</Box>
197+
198+
{/* Bottom bar */}
199+
<Box
200+
sx={{
201+
backgroundColor: theme.palette.background.paper,
202+
borderTop: `1px solid ${theme.palette.divider}`,
203+
px: { xs: 3, md: 8 },
204+
py: 2,
205+
}}
96206
>
97-
Terms and Conditions
98-
</Button>
99-
</footer>
207+
<Box
208+
sx={{
209+
display: 'flex',
210+
justifyContent: 'space-between',
211+
alignItems: 'center',
212+
maxWidth: '1400px',
213+
mx: 'auto',
214+
flexDirection: { xs: 'column', sm: 'row' },
215+
gap: 1,
216+
}}
217+
>
218+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
219+
<Image
220+
src={
221+
theme.palette.mode === 'light'
222+
? '/assets/MOBILTYDATA_logo_light_blue_M.png'
223+
: '/assets/MOBILTYDATA_logo_purple_M.png'
224+
}
225+
alt=''
226+
width={18}
227+
height={18}
228+
style={{ opacity: 0.8 }}
229+
/>
230+
<Typography
231+
sx={{
232+
color: theme.palette.text.secondary,
233+
fontSize: '0.8rem',
234+
fontFamily: fontFamily.secondary,
235+
}}
236+
>
237+
{t('maintainedBy')}
238+
</Typography>
239+
</Box>
240+
<Typography
241+
sx={{
242+
color: theme.palette.text.secondary,
243+
fontSize: '0.8rem',
244+
fontFamily: fontFamily.secondary,
245+
}}
246+
>
247+
{t('copyright', { year: currentYear })}
248+
</Typography>
249+
</Box>
250+
</Box>
251+
</Box>
100252
);
101253
};
102254

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use client';
2+
import React from 'react';
3+
import { Link, Typography, useTheme } from '@mui/material';
4+
import NextLink from 'next/link';
5+
import { fontFamily } from '../Theme';
6+
7+
interface FooterLinkProps {
8+
href: string;
9+
external?: boolean;
10+
children: React.ReactNode;
11+
}
12+
13+
export const FooterLink: React.FC<FooterLinkProps> = ({
14+
href,
15+
external,
16+
children,
17+
}) => {
18+
const theme = useTheme();
19+
return (
20+
<Link
21+
component={NextLink}
22+
href={href}
23+
target={external === true ? '_blank' : undefined}
24+
rel={external === true ? 'noreferrer' : undefined}
25+
sx={{
26+
color: theme.palette.text.secondary,
27+
textDecoration: 'none',
28+
fontSize: theme.typography.body2.fontSize,
29+
fontFamily: fontFamily.secondary,
30+
display: 'block',
31+
marginBottom: 1.5,
32+
transition: 'color 0.2s',
33+
'&:hover': {
34+
color: theme.palette.text.primary,
35+
},
36+
}}
37+
>
38+
{children}
39+
</Link>
40+
);
41+
};
42+
export const FooterColumnTitle: React.FC<{ children: React.ReactNode }> = ({
43+
children,
44+
}) => {
45+
const theme = useTheme();
46+
return (
47+
<Typography
48+
variant='subtitle2'
49+
sx={{
50+
fontWeight: 700,
51+
mb: 2,
52+
fontFamily: fontFamily.secondary,
53+
fontSize: theme.typography.body2.fontSize,
54+
}}
55+
>
56+
{children}
57+
</Typography>
58+
);
59+
};

0 commit comments

Comments
 (0)