Files
ox_lib/web/src/features/menu/list/ListItem.tsx
renzuzu 8eca1698cb feat(web/meu): support images as icons in context and list menu (#230)
* feat: Support image Tag in buttons

in my server. ox_lib is heavily used.
most of sample use cases for this is.
Food image,
Ingredients,
Vehicle Parts,
etc..

i believe font awesome is not enough for some use cases.

i did suggest this on v3 pending PR.
but it seems gets ignored.

here i am gonna try to push this PR.

to use this.
icon must be not existing in the options.

if both icon and image is in options, nothing will appear.

image in metadata will still appear normaly.

* tweak(web/menu): resize render image comparable to FA

* refactor(web/context): use icon prop for images

* refactor(web/list): use icon prop for images

---------

Co-authored-by: Luke <39926192+LukeWasTakenn@users.noreply.github.com>
2023-02-19 13:53:48 +01:00

138 lines
4.1 KiB
TypeScript

import { Box, Group, Stack, Text, Progress, Image } from '@mantine/core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { forwardRef } from 'react';
import CustomCheckbox from './CustomCheckbox';
import type { MenuItem } from '../../../typings';
import { createStyles } from '@mantine/core';
import { isIconUrl } from '../../../utils/isIconUrl';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
interface Props {
item: MenuItem;
index: number;
scrollIndex: number;
checked: boolean;
}
const useStyles = createStyles((theme, params: { iconColor?: string }) => ({
buttonContainer: {
backgroundColor: theme.colors.dark[6],
borderRadius: theme.radius.md,
padding: 2,
height: 60,
scrollMargin: 8,
'&:focus': {
backgroundColor: theme.colors.dark[4],
outline: 'none',
},
},
iconImage: {
maxWidth: 32,
},
buttonWrapper: {
paddingLeft: 5,
paddingRight: 12,
height: '100%',
},
iconContainer: {
display: 'flex',
alignItems: 'center',
width: 32,
height: 32,
},
icon: {
fontSize: 24,
color: params.iconColor || theme.colors.dark[2],
},
label: {
color: theme.colors.dark[2],
textTransform: 'uppercase',
fontSize: 12,
verticalAlign: 'middle',
},
chevronIcon: {
fontSize: 14,
color: theme.colors.dark[2],
},
scrollIndexValue: {
color: theme.colors.dark[2],
textTransform: 'uppercase',
fontSize: 14,
},
progressStack: {
width: '100%',
marginRight: 5,
},
progressLabel: {
verticalAlign: 'middle',
marginBottom: 3,
},
}));
const ListItem = forwardRef<Array<HTMLDivElement | null>, Props>(({ item, index, scrollIndex, checked }, ref) => {
const { classes } = useStyles({ iconColor: item.iconColor });
return (
<Box
tabIndex={index}
className={classes.buttonContainer}
key={`item-${index}`}
ref={(element: HTMLDivElement) => {
if (ref)
// @ts-ignore i cba
return (ref.current = [...ref.current, element]);
}}
>
<Group spacing={15} noWrap className={classes.buttonWrapper}>
{item.icon && (
<Box className={classes.iconContainer}>
{typeof item.icon === 'string' && isIconUrl(item.icon) ? (
<img src={item.icon} alt="Missing image" className={classes.iconImage} />
) : (
<FontAwesomeIcon icon={item.icon as IconProp} className={classes.icon} fixedWidth />
)}
</Box>
)}
{Array.isArray(item.values) ? (
<Group position="apart" w="100%">
<Stack spacing={0} justify="space-between">
<Text className={classes.label}>{item.label}</Text>
<Text>
{typeof item.values[scrollIndex] === 'object'
? // @ts-ignore for some reason even checking the type TS still thinks it's a string
item.values[scrollIndex].label
: item.values[scrollIndex]}
</Text>
</Stack>
<Group spacing={1} position="center">
<FontAwesomeIcon icon="chevron-left" className={classes.chevronIcon} />
<Text className={classes.scrollIndexValue}>
{scrollIndex + 1}/{item.values.length}
</Text>
<FontAwesomeIcon icon="chevron-right" className={classes.chevronIcon} />
</Group>
</Group>
) : item.checked !== undefined ? (
<Group position="apart" w="100%">
<Text>{item.label}</Text>
<CustomCheckbox checked={checked}></CustomCheckbox>
</Group>
) : item.progress !== undefined ? (
<Stack className={classes.progressStack} spacing={0}>
<Text className={classes.progressLabel}>{item.label}</Text>
<Progress
value={item.progress}
color={item.colorScheme || 'dark.0'}
styles={(theme) => ({ root: { backgroundColor: theme.colors.dark[3] } })}
/>
</Stack>
) : (
<Text>{item.label}</Text>
)}
</Group>
</Box>
);
});
export default React.memo(ListItem);