2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

Details image tweaks (#6603)

* Changes for PartThumbTable:

- Limit use of custom styling
- Better display of images

* Fix background color

* Use <StylishText> for titles

* Cleanup details grid

- Use Mantine components
- Simplify structure

* Fix TableThumbProps
This commit is contained in:
Oliver 2024-02-29 11:18:08 +11:00 committed by GitHub
parent cbd2794a7e
commit 05e67d310a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 152 additions and 166 deletions

View File

@ -1,9 +1,11 @@
import { Trans, t } from '@lingui/macro';
import {
AspectRatio,
Button,
Group,
Image,
Modal,
Overlay,
Paper,
Text,
rem,
@ -20,6 +22,7 @@ import { InvenTreeIcon } from '../../functions/icons';
import { useUserState } from '../../states/UserState';
import { PartThumbTable } from '../../tables/part/PartThumbTable';
import { ActionButton } from '../buttons/ActionButton';
import { StylishText } from '../items/StylishText';
import { ApiImage } from './ApiImage';
/**
@ -58,9 +61,9 @@ const backup_image = '/static/img/blank_image.png';
*/
const removeModal = (apiPath: string, setImage: (image: string) => void) =>
modals.openConfirmModal({
title: t`Remove Image`,
title: <StylishText size="xl">{t`Remove Image`}</StylishText>,
children: (
<Text size="sm">
<Text>
<Trans>Remove the associated image from this item?</Trans>
</Text>
),
@ -245,13 +248,8 @@ function ImageActionButtons({
pk: string;
setImage: (image: string) => void;
}) {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Modal opened={opened} onClose={close} title={t`Select image`} size="70%">
<PartThumbTable pk={pk} close={close} setImage={setImage} />
</Modal>
{visible && (
<Group
spacing="xs"
@ -259,24 +257,37 @@ function ImageActionButtons({
>
{actions.selectExisting && (
<ActionButton
icon={<InvenTreeIcon icon="select_image" />}
icon={
<InvenTreeIcon
icon="select_image"
iconProps={{ color: 'white' }}
/>
}
tooltip={t`Select from existing images`}
variant="outline"
size="lg"
tooltipAlignment="top"
onClick={open}
onClick={() => {
modals.open({
title: <StylishText size="xl">{t`Select Image`}</StylishText>,
size: 'xxl',
children: <PartThumbTable pk={pk} setImage={setImage} />
});
}}
/>
)}
{actions.uploadFile && (
<ActionButton
icon={<InvenTreeIcon icon="upload" />}
icon={
<InvenTreeIcon icon="upload" iconProps={{ color: 'white' }} />
}
tooltip={t`Upload new image`}
variant="outline"
size="lg"
tooltipAlignment="top"
onClick={() => {
modals.open({
title: t`Upload Image`,
title: <StylishText size="xl">{t`Upload Image`}</StylishText>,
children: (
<UploadModal apiPath={apiPath} setImage={setImage} />
)
@ -320,19 +331,10 @@ export function DetailsImage(props: DetailImageProps) {
return (
<>
<Paper
ref={ref}
style={{
position: 'relative',
width: `${IMAGE_DIMENSION}px`,
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}
>
<AspectRatio ref={ref} maw={IMAGE_DIMENSION} ratio={1}>
<>
<ApiImage
src={img}
style={{ zIndex: 1 }}
height={IMAGE_DIMENSION}
width={IMAGE_DIMENSION}
onClick={() => {
@ -342,7 +344,8 @@ export function DetailsImage(props: DetailImageProps) {
});
}}
/>
{permissions.hasChangeRole(props.appRole) && (
{permissions.hasChangeRole(props.appRole) && hovered && (
<Overlay color="black" opacity={0.8}>
<ImageActionButtons
visible={hovered}
actions={props.imageActions}
@ -351,8 +354,10 @@ export function DetailsImage(props: DetailImageProps) {
pk={props.pk}
setImage={setAndRefresh}
/>
</Overlay>
)}
</Paper>
</>
</AspectRatio>
</>
);
}

View File

@ -5,6 +5,7 @@ import {
Badge,
CopyButton,
Group,
Paper,
Skeleton,
Table,
Text,
@ -437,7 +438,7 @@ export function DetailsTable({
partIcons?: boolean;
}) {
return (
<Group>
<Paper p="xs" withBorder radius="xs">
<Table striped>
<tbody>
{partIcons && (
@ -475,6 +476,6 @@ export function DetailsTable({
})}
</tbody>
</Table>
</Group>
</Paper>
);
}

View File

@ -1,4 +1,4 @@
import { Paper } from '@mantine/core';
import { Grid, Group, Paper, SimpleGrid } from '@mantine/core';
import {
DetailImageButtonProps,
@ -50,13 +50,11 @@ export function ItemDetails({
partModel: boolean;
}) {
return (
<Paper style={{ display: 'flex', gap: '20px', flexWrap: 'wrap' }}>
<Paper
withBorder
style={{ flexBasis: '49%', display: 'flex', gap: '10px' }}
>
<Paper p="xs">
<SimpleGrid cols={2} spacing="xs" verticalSpacing="xs">
<Grid>
{fields.image && (
<div style={{ flexGrow: '0' }}>
<Grid.Col span={4}>
<DetailsImage
appRole={appRole}
imageActions={fields.image.imageActions}
@ -65,33 +63,26 @@ export function ItemDetails({
refresh={refresh}
pk={params.pk}
/>
</div>
</Grid.Col>
)}
<Grid.Col span={8}>
{fields.left && (
<div style={{ flexGrow: '1' }}>
<DetailsTable
item={params}
fields={fields.left}
partIcons={partModel}
/>
</div>
)}
</Paper>
{fields.right && (
<Paper style={{ flexBasis: '49%' }} withBorder>
<DetailsTable item={params} fields={fields.right} />
</Paper>
)}
</Grid.Col>
</Grid>
{fields.right && <DetailsTable item={params} fields={fields.right} />}
{fields.bottom_left && (
<Paper style={{ flexBasis: '49%' }} withBorder>
<DetailsTable item={params} fields={fields.bottom_left} />
</Paper>
)}
{fields.bottom_right && (
<Paper style={{ flexBasis: '49%' }} withBorder>
<DetailsTable item={params} fields={fields.bottom_right} />
</Paper>
)}
</SimpleGrid>
</Paper>
);
}

View File

@ -1,6 +1,18 @@
import { t } from '@lingui/macro';
import { Button, Paper, Skeleton, Text, TextInput } from '@mantine/core';
import { Trans, t } from '@lingui/macro';
import {
AspectRatio,
Button,
Divider,
Group,
Paper,
SimpleGrid,
Skeleton,
Stack,
Text,
TextInput
} from '@mantine/core';
import { useHover } from '@mantine/hooks';
import { modals } from '@mantine/modals';
import { useQuery } from '@tanstack/react-query';
import React, { Suspense, useEffect, useState } from 'react';
@ -17,7 +29,6 @@ export type ThumbTableProps = {
limit?: number;
offset?: number;
search?: string;
close: () => void;
setImage: (image: string) => void;
};
@ -62,29 +73,19 @@ function PartThumbComponent({ selected, element, selectImage }: ThumbProps) {
return (
<Paper
withBorder
style={{
backgroundColor: color,
padding: '5px',
display: 'flex',
flex: '0 1 150px',
flexFlow: 'column wrap',
placeContent: 'center space-between'
}}
style={{ backgroundColor: color }}
p="sm"
ref={ref}
onClick={() => selectImage(element.image)}
>
<div
style={{
display: 'flex',
alignItems: 'center',
flexGrow: 1
}}
>
<Stack justify="space-between">
<AspectRatio ratio={1}>
<Thumbnail size={120} src={src} align="center"></Thumbnail>
</div>
<Text style={{ alignSelf: 'center', overflowWrap: 'anywhere' }}>
</AspectRatio>
<Text size="xs">
{element.image.split('/')[1]} ({element.count})
</Text>
</Stack>
</Paper>
);
}
@ -95,7 +96,6 @@ function PartThumbComponent({ selected, element, selectImage }: ThumbProps) {
async function setNewImage(
image: string | null,
pk: string,
close: () => void,
setImage: (image: string) => void
) {
// No need to do anything if no image is selected
@ -110,7 +110,7 @@ async function setNewImage(
// Update image component and close modal if update was successful
if (response.data.image.includes(image)) {
setImage(response.data.image);
close();
modals.closeAll();
}
}
@ -118,11 +118,10 @@ async function setNewImage(
* Renders a "table" of thumbnails
*/
export function PartThumbTable({
limit = 25,
limit = 24,
offset = 0,
search = '',
pk,
close,
setImage
}: ThumbTableProps) {
const [img, selectImage] = useState<string | null>(null);
@ -155,24 +154,21 @@ export function PartThumbTable({
return (
<>
<Suspense>
<Paper
style={{
display: 'flex',
alignItems: 'stretch',
placeContent: 'stretch center',
flexWrap: 'wrap',
gap: '10px'
}}
>
<Divider />
<Paper p="sm">
<>
<SimpleGrid cols={8}>
{!thumbQuery.isFetching
? thumbQuery.data?.data.map((data: ImageElement, index: number) => (
? thumbQuery.data?.data.map(
(data: ImageElement, index: number) => (
<PartThumbComponent
element={data}
key={index}
selected={img}
selectImage={selectImage}
/>
))
)
)
: [...Array(limit)].map((elem, idx) => (
<Skeleton
height={150}
@ -182,22 +178,14 @@ export function PartThumbTable({
style={{ padding: '5px' }}
/>
))}
</SimpleGrid>
</>
</Paper>
</Suspense>
<Paper
style={{
position: 'sticky',
bottom: 0,
left: 0,
right: 0,
height: '60px',
zIndex: 1,
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between'
}}
>
<Divider />
<Paper p="sm">
<Group position="apart">
<TextInput
placeholder={t`Search...`}
onChange={(event) => {
@ -206,10 +194,11 @@ export function PartThumbTable({
/>
<Button
disabled={!img}
onClick={() => setNewImage(img, pk, close, setImage)}
onClick={() => setNewImage(img, pk, setImage)}
>
Submit
<Trans>Select</Trans>
</Button>
</Group>
</Paper>
</>
);