All files / src/components/TableOfContents TableOfContents.tsx

100% Statements 11/11
100% Branches 0/0
100% Functions 6/6
100% Lines 11/11

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112                                                  7x 7x 7x     7x   14x 14x           1x                   7x                     1x                                   2x               1x                                                  
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import Drawer from '@mui/material/Drawer';
import MenuIcon from '@mui/icons-material/Menu';
 
interface TocProps {
  sections: readonly [string, string][];  // [subKey, textKey]
  makeId: (key: string) => string;
  titleKey: string;                       // ex. 'legal.subtitleTableOfContents'
  namespace: string;                      // ex. 'legal'
}
 
export function TableOfContents({
  sections,
  makeId,
  titleKey,
  namespace,
}: TocProps) {
  const theme = useTheme();
  const { t } = useTranslation(namespace);
  const [open, setOpen] = useState(false);
 
  const TocList = (
    <List disablePadding>
      {sections.map(([subKey]) => {
        const anchor = makeId(subKey);
        return (
          <ListItemButton
            key={subKey}
            component="a"
            href={`#${anchor}`}
            sx={{ pl: 2 }}
            onClick={() => setOpen(false)}
          >
            {/* on traduit la clé du titre de section */}
            <ListItemText primary={t(`${namespace}.${subKey}`)} />
          </ListItemButton>
        );
      })}
    </List>
  );
 
  return (
    <>
      {/* Sidebar desktop */}
      <Box
        component="nav"
        sx={{
          display: { xs: 'none', md: 'block' },
          position: 'sticky',
          top: theme.mixins.toolbar.minHeight,
          width: 240,
          bgcolor: 'background.paper',
          border: theme => `1px solid ${theme.palette.divider}`,
          borderRadius: 1,
          p: 2,
          flexShrink: 0,
          overflowY: 'auto',
          WebkitOverflowScrolling: 'touch',
          overscrollBehaviorY: 'contain',
        }}
      >
        <Typography variant="h6" gutterBottom>
          {t(titleKey)}
        </Typography>
        {TocList}
      </Box>
 
      {/* Drawer mobile */}
      <Box sx={{ display: { xs: 'block', md: 'none' }, mb: 2 }}>
        <IconButton
          onClick={() => setOpen(true)}
          aria-label={t(titleKey)}
        >
          <MenuIcon />
        </IconButton>
        <Drawer
          anchor="left"
          open={open}
          onClose={() => setOpen(false)}
          ModalProps={{ keepMounted: true }}
        >
          <Box
            role="presentation"
            sx={{
              width: 250,
              p: 2,
              bgcolor: 'background.paper',
              height: '100%',
              overflowY: 'auto',
              WebkitOverflowScrolling: 'touch',
              overscrollBehaviorY: 'contain',
            }}
          >
            <Typography variant="h6" gutterBottom>
              {t(titleKey)}
            </Typography>
            {TocList}
          </Box>
        </Drawer>
      </Box>
    </>
  );
}