mirror of
https://github.com/inventree/InvenTree.git
synced 2026-09-02 10:18:42 +00:00
feat(frontend): lib make Detaildrawer available (#11827)
* feat(frontend): lib make Detaildrawer available Co-authored-by: Copilot <copilot@github.com> * move StylishText to lib Co-authored-by: Copilot <copilot@github.com> * add changelog entry Co-authored-by: Copilot <copilot@github.com> * fix import path --------- Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import {
|
||||
type MantineSize,
|
||||
Text,
|
||||
darken,
|
||||
getThemeColor,
|
||||
useMantineTheme
|
||||
} from '@mantine/core';
|
||||
import { useMemo } from 'react';
|
||||
import type { JSX } from 'react';
|
||||
|
||||
// Hook that memoizes the gradient color based on the primary color of the theme
|
||||
const useThematicGradient = () => {
|
||||
const theme = useMantineTheme();
|
||||
|
||||
const primary = useMemo(() => {
|
||||
return getThemeColor(theme.primaryColor, theme);
|
||||
}, [theme]);
|
||||
|
||||
const secondary = useMemo(() => darken(primary, 0.25), [primary]);
|
||||
|
||||
return useMemo(() => {
|
||||
return { primary, secondary };
|
||||
}, [primary, secondary]);
|
||||
};
|
||||
|
||||
// A stylish text component that uses the primary color of the theme
|
||||
export function StylishText({
|
||||
children,
|
||||
size
|
||||
}: Readonly<{
|
||||
children: JSX.Element | string;
|
||||
size?: MantineSize;
|
||||
}>) {
|
||||
const { primary, secondary } = useThematicGradient();
|
||||
|
||||
return (
|
||||
<Text
|
||||
fw={700}
|
||||
size={size ?? 'xl'}
|
||||
variant='gradient'
|
||||
gradient={{ from: primary.toString(), to: secondary.toString() }}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const flex = style({
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
});
|
||||
@@ -0,0 +1,108 @@
|
||||
import { ActionIcon, Divider, Drawer, Group, Stack, Text } from '@mantine/core';
|
||||
import { IconChevronLeft } from '@tabler/icons-react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { Link, Route, Routes, useNavigate, useParams } from 'react-router-dom';
|
||||
import type { To } from 'react-router-dom';
|
||||
|
||||
import type { UiSizeType } from '../../types/Core';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useLocalLibState } from '../../states/LocalLibState';
|
||||
import { StylishText } from '../StylishText';
|
||||
import * as classes from './DetailDrawer.css';
|
||||
|
||||
/**
|
||||
* @param title - drawer title
|
||||
* @param position - drawer position
|
||||
* @param renderContent - function used to render the drawer content
|
||||
* @param urlPrefix - set an additional url segment, useful when multiple drawers are rendered on one page (e.g. "user/")
|
||||
*/
|
||||
export interface DrawerProps {
|
||||
title: string;
|
||||
position?: 'right' | 'left';
|
||||
renderContent: (id?: string) => React.ReactNode;
|
||||
urlPrefix?: string;
|
||||
size?: UiSizeType;
|
||||
closeOnEscape?: boolean;
|
||||
}
|
||||
|
||||
function DetailDrawerComponent({
|
||||
title,
|
||||
position = 'right',
|
||||
size,
|
||||
closeOnEscape = true,
|
||||
renderContent
|
||||
}: Readonly<DrawerProps>) {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
|
||||
const content = renderContent(id);
|
||||
const opened = useMemo(() => !!id && !!content, [id, content]);
|
||||
|
||||
const [detailDrawerStack, addDetailDrawer] = useLocalLibState(
|
||||
useShallow((state) => [state.detailDrawerStack, state.addDetailDrawer])
|
||||
);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
opened={opened}
|
||||
onClose={() => {
|
||||
navigate('../');
|
||||
addDetailDrawer(false);
|
||||
}}
|
||||
position={position}
|
||||
closeOnEscape={closeOnEscape}
|
||||
size={size}
|
||||
classNames={{ root: classes.flex, body: classes.flex }}
|
||||
scrollAreaComponent={Stack}
|
||||
title={
|
||||
<Group>
|
||||
{detailDrawerStack > 0 && (
|
||||
<ActionIcon
|
||||
variant='outline'
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
addDetailDrawer(-1);
|
||||
}}
|
||||
>
|
||||
<IconChevronLeft />
|
||||
</ActionIcon>
|
||||
)}
|
||||
<StylishText size='xl'>{title}</StylishText>
|
||||
</Group>
|
||||
}
|
||||
>
|
||||
<Stack gap={'xs'} className={classes.flex}>
|
||||
<Divider />
|
||||
{content}
|
||||
</Stack>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
||||
export function DetailDrawer(props: Readonly<DrawerProps>) {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path=':id?/' element={<DetailDrawerComponent {...props} />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
export function DetailDrawerLink({
|
||||
to,
|
||||
text
|
||||
}: Readonly<{ to: To; text: string }>) {
|
||||
const addDetailDrawer = useLocalLibState(
|
||||
useShallow((state) => state.addDetailDrawer)
|
||||
);
|
||||
|
||||
const onNavigate = useCallback(() => {
|
||||
addDetailDrawer(1);
|
||||
}, [addDetailDrawer]);
|
||||
|
||||
return (
|
||||
<Link to={to} onClick={onNavigate}>
|
||||
<Text>{text}</Text>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -132,6 +132,13 @@ export {
|
||||
type TableStateExtraProps
|
||||
} from './hooks/UseTable';
|
||||
|
||||
export {
|
||||
type DrawerProps,
|
||||
DetailDrawer,
|
||||
DetailDrawerLink
|
||||
} from './components/nav/DetailDrawer';
|
||||
export { StylishText } from './components/StylishText';
|
||||
|
||||
// State management
|
||||
export {
|
||||
type StoredTableStateProps,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
export const useLocalLibState = create<LocalLibStateProps>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
detailDrawerStack: 0,
|
||||
addDetailDrawer: (value) => {
|
||||
set({
|
||||
detailDrawerStack:
|
||||
value === false ? 0 : get().detailDrawerStack + value
|
||||
});
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: 'session-settings-inventreedb_lib'
|
||||
}
|
||||
)
|
||||
);
|
||||
export interface LocalLibStateProps {
|
||||
detailDrawerStack: number;
|
||||
addDetailDrawer: (value: number | false) => void;
|
||||
}
|
||||
Reference in New Issue
Block a user