aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/templates/layout/site-footer/site-footer.tsx
blob: b852b326d37bc7d12e4c5812dc1d60beb04f0a08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { type ForwardRefRenderFunction, forwardRef } from 'react';
import { useIntl } from 'react-intl';
import { CONFIG } from '../../../../utils/config';
import { ROUTES } from '../../../../utils/constants';
import { useScrollPosition } from '../../../../utils/hooks';
import { Footer, type FooterProps, Icon } from '../../../atoms';
import {
  BackToTop,
  Colophon,
  type ColophonLink,
  Copyright,
} from '../../../molecules';
import styles from './site-footer.module.scss';

export type SiteFooterProps = Omit<FooterProps, 'children'> & {
  /**
   * An id that will be use as anchor for the back to top button.
   */
  topId?: string;
};

const SiteFooterWithRef: ForwardRefRenderFunction<
  HTMLElement,
  SiteFooterProps
> = ({ className = '', topId, ...props }, ref) => {
  const footerClass = `${styles.footer} ${className}`;
  const intl = useIntl();
  const licenseName = intl.formatMessage({
    defaultMessage: 'CC BY SA',
    description: 'SiteFooter: the license name',
    id: 'iTLvLX',
  });
  const backToTop = intl.formatMessage({
    defaultMessage: 'Back to top',
    description: 'SiteFooter: an accessible name for the back to top button',
    id: 'OHvb01',
  });
  const footerNav: ColophonLink[] = [
    {
      id: 'legal-notice',
      label: intl.formatMessage({
        defaultMessage: 'Legal notice',
        description: 'SiteFooter: Legal notice link label',
        id: 'lsmD4c',
      }),
      href: ROUTES.LEGAL_NOTICE,
    },
  ];
  const scrollPos = useScrollPosition();
  const backToTopVisibilityBreakpoint = 300;
  const backToTopClassName = [
    styles['back-to-top'],
    styles[
      scrollPos.y > backToTopVisibilityBreakpoint
        ? 'back-to-top--visible'
        : 'back-to-top--hidden'
    ],
  ].join(' ');
  const backToTopAnchor = topId ? `#${topId}` : undefined;

  return (
    <Footer {...props} className={footerClass} ref={ref}>
      <Colophon
        copyright={
          <Copyright
            from={CONFIG.copyright.startYear}
            owner={CONFIG.name}
            to={CONFIG.copyright.endYear}
          />
        }
        license={
          <Icon
            heading={licenseName}
            // eslint-disable-next-line react/jsx-no-literals
            shape="cc-by-sa"
            // eslint-disable-next-line react/jsx-no-literals
            size="lg"
          />
        }
        links={footerNav}
      />
      {backToTopAnchor ? (
        <BackToTop
          anchor={backToTopAnchor}
          className={backToTopClassName}
          label={backToTop}
        />
      ) : null}
    </Footer>
  );
};

export const SiteFooter = forwardRef(SiteFooterWithRef);