mirror of
https://github.com/inventree/InvenTree.git
synced 2026-05-02 15:54:29 +00:00
[P-UI] Home page (#5344)
* Add new start page * [FR/P-UI] Home/Start page - widgets * load widgets dynamic * code cleanup * remove lodash * refactor and rename to WidgetLayout * Add CSS serving * removed unneeded complexity * clean up UI; switch to menu for controls * change signature * added hotkey * removed hover * removed dummy widget * Add translations * fix test * uses real data for getting started * adapted style for GettingStartedCard * added placeholder usage to GettingStartedCard
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@lingui/core": "^4.3.0",
|
||||
"@lingui/react": "^4.3.0",
|
||||
"@mantine/carousel": "^6.0.17",
|
||||
"@mantine/core": "^6.0.17",
|
||||
"@mantine/dates": "^6.0.17",
|
||||
"@mantine/dropzone": "^6.0.17",
|
||||
@@ -29,10 +30,12 @@
|
||||
"@tanstack/react-query": "^4.32.0",
|
||||
"axios": "^1.4.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"embla-carousel-react": "^8.0.0-rc11",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"mantine-datatable": "^2.9.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-router-dom": "^6.14.2",
|
||||
"zustand": "^4.3.9"
|
||||
},
|
||||
@@ -46,6 +49,7 @@
|
||||
"@types/node": "^20.4.4",
|
||||
"@types/react": "^18.2.15",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/react-grid-layout": "^1.3.2",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-react": "^4.0.3",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { Carousel } from '@mantine/carousel';
|
||||
import {
|
||||
Anchor,
|
||||
Button,
|
||||
Paper,
|
||||
Text,
|
||||
Title,
|
||||
createStyles,
|
||||
rem
|
||||
} from '@mantine/core';
|
||||
|
||||
import { DocumentationLinkItem } from './DocumentationLinks';
|
||||
import { PlaceholderPill } from './Placeholder';
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
card: {
|
||||
height: rem(170),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-start',
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center'
|
||||
},
|
||||
|
||||
title: {
|
||||
fontWeight: 900,
|
||||
color:
|
||||
theme.colorScheme === 'dark' ? theme.colors.white : theme.colors.dark,
|
||||
lineHeight: 1.2,
|
||||
fontSize: rem(32),
|
||||
marginTop: 0
|
||||
},
|
||||
|
||||
category: {
|
||||
color:
|
||||
theme.colorScheme === 'dark' ? theme.colors.white : theme.colors.dark,
|
||||
opacity: 0.7,
|
||||
fontWeight: 700
|
||||
}
|
||||
}));
|
||||
|
||||
function StartedCard({
|
||||
title,
|
||||
description,
|
||||
link,
|
||||
placeholder
|
||||
}: DocumentationLinkItem) {
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<Paper shadow="md" p="xl" radius="md" className={classes.card}>
|
||||
<div>
|
||||
<Title order={3} className={classes.title}>
|
||||
{title} {placeholder && <PlaceholderPill />}
|
||||
</Title>
|
||||
<Text size="sm" className={classes.category} lineClamp={2}>
|
||||
{description}
|
||||
</Text>
|
||||
</div>
|
||||
<Anchor href={link} target="_blank">
|
||||
<Button>
|
||||
<Trans>Read more</Trans>
|
||||
</Button>
|
||||
</Anchor>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
export function GettingStartedCarousel({
|
||||
items
|
||||
}: {
|
||||
items: DocumentationLinkItem[];
|
||||
}) {
|
||||
const slides = items.map((item) => (
|
||||
<Carousel.Slide key={item.id}>
|
||||
<StartedCard {...item} />
|
||||
</Carousel.Slide>
|
||||
));
|
||||
|
||||
return (
|
||||
<Carousel
|
||||
slideSize="50%"
|
||||
breakpoints={[{ maxWidth: 'sm', slideSize: '100%', slideGap: rem(2) }]}
|
||||
slideGap="xl"
|
||||
align="start"
|
||||
>
|
||||
{slides}
|
||||
</Carousel>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { SimpleGrid, Title } from '@mantine/core';
|
||||
|
||||
import { ColorToggle } from '../items/ColorToggle';
|
||||
import { LanguageSelect } from '../items/LanguageSelect';
|
||||
|
||||
export default function DisplayWidget() {
|
||||
return (
|
||||
<span>
|
||||
<Title order={5}>
|
||||
<Trans>Display Settings</Trans>
|
||||
</Title>
|
||||
<SimpleGrid cols={2} spacing={0}>
|
||||
<div>
|
||||
<Trans>Color Mode</Trans>
|
||||
</div>
|
||||
<div>
|
||||
<ColorToggle />
|
||||
</div>
|
||||
<div>
|
||||
<Trans>Language</Trans>
|
||||
</div>
|
||||
<div>
|
||||
<LanguageSelect />
|
||||
</div>
|
||||
</SimpleGrid>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { Button, Stack, Title } from '@mantine/core';
|
||||
import { IconExternalLink } from '@tabler/icons-react';
|
||||
|
||||
export default function FeedbackWidget() {
|
||||
return (
|
||||
<Stack
|
||||
sx={(theme) => ({
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark'
|
||||
? theme.colors.gray[9]
|
||||
: theme.colors.gray[1],
|
||||
borderRadius: theme.radius.md
|
||||
})}
|
||||
p={15}
|
||||
>
|
||||
<Title order={5}>
|
||||
<Trans>Something is new: Platform UI</Trans>
|
||||
</Title>
|
||||
<Trans>
|
||||
We are building a new UI with a modern stack. What you currently see is
|
||||
not fixed and will be redesigned but demonstrates the UI/UX
|
||||
possibilities we will have going forward.
|
||||
</Trans>
|
||||
<Button
|
||||
component="a"
|
||||
href="https://github.com/inventree/InvenTree/discussions/5328"
|
||||
variant="outline"
|
||||
leftIcon={<IconExternalLink size="0.9rem" />}
|
||||
>
|
||||
<Trans>Provide Feedback</Trans>
|
||||
</Button>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { Title } from '@mantine/core';
|
||||
|
||||
import { navDocLinks } from '../../defaults/links';
|
||||
import { GettingStartedCarousel } from '../items/GettingStartedCarousel';
|
||||
|
||||
export default function GetStartedWidget() {
|
||||
return (
|
||||
<span>
|
||||
<Title order={5}>
|
||||
<Trans>Getting started</Trans>
|
||||
</Title>
|
||||
<GettingStartedCarousel items={navDocLinks} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
import { Trans } from '@lingui/macro';
|
||||
import {
|
||||
ActionIcon,
|
||||
Container,
|
||||
Group,
|
||||
Indicator,
|
||||
createStyles
|
||||
} from '@mantine/core';
|
||||
import { Menu, Text } from '@mantine/core';
|
||||
import { useDisclosure, useHotkeys } from '@mantine/hooks';
|
||||
import {
|
||||
IconArrowBackUpDouble,
|
||||
IconDotsVertical,
|
||||
IconLayout2,
|
||||
IconSquare,
|
||||
IconSquareCheck
|
||||
} from '@tabler/icons-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Responsive, WidthProvider } from 'react-grid-layout';
|
||||
|
||||
const ReactGridLayout = WidthProvider(Responsive);
|
||||
|
||||
interface LayoutStorage {
|
||||
[key: string]: {};
|
||||
}
|
||||
|
||||
const compactType = 'vertical';
|
||||
|
||||
const useItemStyle = createStyles((theme) => ({
|
||||
backgroundItem: {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.white,
|
||||
maxWidth: '100%',
|
||||
padding: '8px',
|
||||
boxShadow: theme.shadows.md
|
||||
},
|
||||
|
||||
baseItem: {
|
||||
maxWidth: '100%',
|
||||
padding: '8px'
|
||||
}
|
||||
}));
|
||||
|
||||
export interface LayoutItemType {
|
||||
i: number;
|
||||
val: string | JSX.Element | JSX.Element[] | (() => JSX.Element);
|
||||
w?: number;
|
||||
h?: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
minH?: number;
|
||||
}
|
||||
|
||||
export function WidgetLayout({
|
||||
items = [],
|
||||
className = 'layout',
|
||||
localstorageName = 'argl',
|
||||
rowHeight = 30
|
||||
}: {
|
||||
items: LayoutItemType[];
|
||||
className?: string;
|
||||
localstorageName?: string;
|
||||
rowHeight?: number;
|
||||
}) {
|
||||
const [layouts, setLayouts] = useState({});
|
||||
const [editable, setEditable] = useDisclosure(false);
|
||||
const [boxShown, setBoxShown] = useDisclosure(true);
|
||||
const { classes } = useItemStyle();
|
||||
|
||||
useEffect(() => {
|
||||
let layout = getFromLS('layouts') || [];
|
||||
const new_layout = JSON.parse(JSON.stringify(layout));
|
||||
setLayouts(new_layout);
|
||||
}, []);
|
||||
|
||||
function getFromLS(key: string) {
|
||||
let ls: LayoutStorage = {};
|
||||
if (localStorage) {
|
||||
try {
|
||||
ls = JSON.parse(localStorage.getItem(localstorageName) || '') || {};
|
||||
} catch (e) {
|
||||
/*Ignore*/
|
||||
}
|
||||
}
|
||||
return ls[key];
|
||||
}
|
||||
|
||||
function saveToLS(key: string, value: any) {
|
||||
if (localStorage) {
|
||||
localStorage.setItem(
|
||||
localstorageName,
|
||||
JSON.stringify({
|
||||
[key]: value
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function resetLayout() {
|
||||
setLayouts({});
|
||||
}
|
||||
|
||||
function onLayoutChange(layout: any, layouts: any) {
|
||||
saveToLS('layouts', layouts);
|
||||
setLayouts(layouts);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<WidgetControlBar
|
||||
editable={editable}
|
||||
editFnc={setEditable.toggle}
|
||||
resetLayout={resetLayout}
|
||||
boxShown={boxShown}
|
||||
boxFnc={setBoxShown.toggle}
|
||||
/>
|
||||
{layouts ? (
|
||||
<ReactGridLayout
|
||||
className={className}
|
||||
cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
|
||||
rowHeight={rowHeight}
|
||||
layouts={layouts}
|
||||
onLayoutChange={(layout, layouts) => onLayoutChange(layout, layouts)}
|
||||
compactType={compactType}
|
||||
isDraggable={editable}
|
||||
isResizable={editable}
|
||||
>
|
||||
{items.map((item) => {
|
||||
return LayoutItem(item, boxShown, classes);
|
||||
})}
|
||||
</ReactGridLayout>
|
||||
) : (
|
||||
<div>
|
||||
<Trans>Loading</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function WidgetControlBar({
|
||||
editable,
|
||||
editFnc,
|
||||
resetLayout,
|
||||
boxShown,
|
||||
boxFnc
|
||||
}: {
|
||||
editable: boolean;
|
||||
editFnc: () => void;
|
||||
resetLayout: () => void;
|
||||
boxShown: boolean;
|
||||
boxFnc: () => void;
|
||||
}) {
|
||||
useHotkeys([['mod+E', () => editFnc()]]);
|
||||
|
||||
return (
|
||||
<Group position="right">
|
||||
<Menu
|
||||
shadow="md"
|
||||
width={200}
|
||||
openDelay={100}
|
||||
closeDelay={400}
|
||||
position="bottom-end"
|
||||
>
|
||||
<Menu.Target>
|
||||
<Indicator
|
||||
color="red"
|
||||
position="bottom-start"
|
||||
processing
|
||||
disabled={!editable}
|
||||
>
|
||||
<ActionIcon variant="transparent">
|
||||
<IconDotsVertical />
|
||||
</ActionIcon>
|
||||
</Indicator>
|
||||
</Menu.Target>
|
||||
|
||||
<Menu.Dropdown>
|
||||
<Menu.Label>
|
||||
<Trans>Layout</Trans>
|
||||
</Menu.Label>
|
||||
<Menu.Item
|
||||
icon={<IconArrowBackUpDouble size={14} />}
|
||||
onClick={resetLayout}
|
||||
>
|
||||
<Trans>Reset Layout</Trans>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
icon={
|
||||
<IconLayout2 size={14} color={editable ? 'red' : undefined} />
|
||||
}
|
||||
onClick={editFnc}
|
||||
rightSection={
|
||||
<Text size="xs" color="dimmed">
|
||||
⌘E
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{editable ? <Trans>Stop Edit</Trans> : <Trans>Edit Layout</Trans>}
|
||||
</Menu.Item>
|
||||
|
||||
<Menu.Divider />
|
||||
|
||||
<Menu.Label>
|
||||
<Trans>Appearance</Trans>
|
||||
</Menu.Label>
|
||||
<Menu.Item
|
||||
icon={
|
||||
boxShown ? (
|
||||
<IconSquareCheck size={14} />
|
||||
) : (
|
||||
<IconSquare size={14} />
|
||||
)
|
||||
}
|
||||
onClick={boxFnc}
|
||||
>
|
||||
<Trans>Show Boxes</Trans>
|
||||
</Menu.Item>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
function LayoutItem(
|
||||
item: any,
|
||||
backgroundColor: boolean,
|
||||
classes: { backgroundItem: string; baseItem: string }
|
||||
) {
|
||||
return (
|
||||
<Container
|
||||
key={item.i}
|
||||
data-grid={{
|
||||
w: item.w || 3,
|
||||
h: item.h || 3,
|
||||
x: item.x || 0,
|
||||
y: item.y || 0,
|
||||
minH: item.minH || undefined,
|
||||
minW: item.minW || undefined
|
||||
}}
|
||||
className={backgroundColor ? classes.backgroundItem : classes.baseItem}
|
||||
>
|
||||
{item.val}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@@ -17,3 +17,8 @@ export const Loadable = (Component: any) => (props: JSX.IntrinsicAttributes) =>
|
||||
<Component {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
export function LoadingItem({ item }: { item: any }): JSX.Element {
|
||||
const Itm = Loadable(item);
|
||||
return <Itm />;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import 'react-grid-layout/css/styles.css';
|
||||
import 'react-resizable/css/styles.css';
|
||||
|
||||
import App from './App';
|
||||
|
||||
|
||||
@@ -1,18 +1,63 @@
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { Group } from '@mantine/core';
|
||||
import { Title } from '@mantine/core';
|
||||
import { lazy } from 'react';
|
||||
|
||||
import { PlaceholderPill } from '../../components/items/Placeholder';
|
||||
import { StylishText } from '../../components/items/StylishText';
|
||||
import {
|
||||
LayoutItemType,
|
||||
WidgetLayout
|
||||
} from '../../components/widgets/WidgetLayout';
|
||||
import { LoadingItem } from '../../functions/loading';
|
||||
import { useApiState } from '../../states/ApiState';
|
||||
|
||||
const vals: LayoutItemType[] = [
|
||||
{
|
||||
i: 1,
|
||||
val: (
|
||||
<LoadingItem
|
||||
item={lazy(() => import('../../components/widgets/GetStartedWidget'))}
|
||||
/>
|
||||
),
|
||||
w: 12,
|
||||
h: 6,
|
||||
x: 0,
|
||||
y: 0,
|
||||
minH: 6
|
||||
},
|
||||
{
|
||||
i: 2,
|
||||
val: (
|
||||
<LoadingItem
|
||||
item={lazy(() => import('../../components/widgets/DisplayWidget'))}
|
||||
/>
|
||||
),
|
||||
w: 3,
|
||||
h: 3,
|
||||
x: 0,
|
||||
y: 7,
|
||||
minH: 3
|
||||
},
|
||||
{
|
||||
i: 4,
|
||||
val: (
|
||||
<LoadingItem
|
||||
item={lazy(() => import('../../components/widgets/FeedbackWidget'))}
|
||||
/>
|
||||
),
|
||||
w: 4,
|
||||
h: 6,
|
||||
x: 0,
|
||||
y: 9
|
||||
}
|
||||
];
|
||||
|
||||
export default function Home() {
|
||||
const [username] = useApiState((state) => [state.user?.name]);
|
||||
return (
|
||||
<>
|
||||
<Group>
|
||||
<StylishText>
|
||||
<Trans>Home</Trans>
|
||||
</StylishText>
|
||||
<PlaceholderPill />
|
||||
</Group>
|
||||
<Title order={1}>
|
||||
<Trans>Welcome to your Dashboard{username && `, ${username}`}</Trans>
|
||||
</Title>
|
||||
<WidgetLayout items={vals} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,5 +11,9 @@ test('Basic Platform UI test', async ({ page }) => {
|
||||
await page.goto('./platform/');
|
||||
|
||||
await expect(page).toHaveTitle('InvenTree Demo Server');
|
||||
await expect(page.getByText('Home').nth(1)).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('heading', {
|
||||
name: 'Welcome to your Dashboard, Ally Access'
|
||||
})
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
+70
-1
@@ -877,6 +877,13 @@
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@lingui/core" "4.3.0"
|
||||
|
||||
"@mantine/carousel@^6.0.17":
|
||||
version "6.0.17"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-6.0.17.tgz#d31fc9bc9ef14bd5ea3e9162d4a130b904cb478e"
|
||||
integrity sha512-cKX7zGmWVXdq/mPff5QYaHLR2X6bujbR4YZ3Hs3TD8KuySTZDOHipUD9IAVH1DtYJRE0+FIRb6OeZ7X9/N2Erg==
|
||||
dependencies:
|
||||
"@mantine/utils" "6.0.17"
|
||||
|
||||
"@mantine/core@^6.0.17":
|
||||
version "6.0.17"
|
||||
resolved "https://registry.npmjs.org/@mantine/core/-/core-6.0.17.tgz"
|
||||
@@ -1167,6 +1174,13 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-grid-layout@^1.3.2":
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-grid-layout/-/react-grid-layout-1.3.2.tgz#9f195666a018a5ae2b773887e3b552cb4378d67f"
|
||||
integrity sha512-ZzpBEOC1JTQ7MGe1h1cPKSLP4jSWuxc+yvT4TsAlEW9+EFPzAf8nxQfFd7ea9gL17Em7PbwJZAsiwfQQBUklZQ==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-router-dom@^5.3.3":
|
||||
version "5.3.3"
|
||||
resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz"
|
||||
@@ -1442,6 +1456,11 @@ clsx@1.1.1:
|
||||
resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz"
|
||||
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
|
||||
|
||||
clsx@^1.1.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
|
||||
@@ -1578,6 +1597,24 @@ electron-to-chromium@^1.4.431:
|
||||
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.468.tgz"
|
||||
integrity sha512-6M1qyhaJOt7rQtNti1lBA0GwclPH+oKCmsra/hkcWs5INLxfXXD/dtdnaKUYQu/pjOBP/8Osoe4mAcNvvzoFag==
|
||||
|
||||
embla-carousel-react@^8.0.0-rc11:
|
||||
version "8.0.0-rc11"
|
||||
resolved "https://registry.yarnpkg.com/embla-carousel-react/-/embla-carousel-react-8.0.0-rc11.tgz#0e2fde5cafa3cae9c30721e18aee648599527994"
|
||||
integrity sha512-hXOAUMOIa0GF5BtdTTqBuKcjgU+ipul6thTCXOZttqnu2c6VS3SIzUUT+onIIEw+AptzKJcPwGcoAByAGa9eJw==
|
||||
dependencies:
|
||||
embla-carousel "8.0.0-rc11"
|
||||
embla-carousel-reactive-utils "8.0.0-rc11"
|
||||
|
||||
embla-carousel-reactive-utils@8.0.0-rc11:
|
||||
version "8.0.0-rc11"
|
||||
resolved "https://registry.yarnpkg.com/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.0.0-rc11.tgz#d5493bd2bfeb68b1cbf65d4c836a4d36779a03de"
|
||||
integrity sha512-pDNVJNCn0dybLkHw93My+cMfkRQ5oLZff6ZCwgmrw+96aPiZUyo5ANywz8Lb70SWWgD/TNBRrtQCquvjHS31Sg==
|
||||
|
||||
embla-carousel@8.0.0-rc11:
|
||||
version "8.0.0-rc11"
|
||||
resolved "https://registry.yarnpkg.com/embla-carousel/-/embla-carousel-8.0.0-rc11.tgz#700ab6b3e4825ef9e6ac83238b81e3e1a316c3f4"
|
||||
integrity sha512-Toeaug98PGYzSY56p/xsa+u4zbQbAXgGymwEDUc2wqT+1XCnnUsH42MClglhABJQbobwDYxOabhJrfXyJKUMig==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
|
||||
@@ -1987,6 +2024,11 @@ lodash.get@^4.4.2:
|
||||
resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz"
|
||||
integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
|
||||
|
||||
lodash.isequal@^4.0.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz"
|
||||
@@ -2231,7 +2273,7 @@ pretty-format@^29.6.1:
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^18.0.0"
|
||||
|
||||
prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
prop-types@15.x, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@@ -2270,6 +2312,14 @@ react-dom@^18.2.0:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.0"
|
||||
|
||||
react-draggable@^4.0.0, react-draggable@^4.0.3:
|
||||
version "4.4.5"
|
||||
resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.5.tgz#9e37fe7ce1a4cf843030f521a0a4cc41886d7e7c"
|
||||
integrity sha512-OMHzJdyJbYTZo4uQE393fHcqqPYsEtkjfMgvCHr6rejT+Ezn4OZbNyGH50vv+SunC1RMvwOTSWkEODQLzw1M9g==
|
||||
dependencies:
|
||||
clsx "^1.1.1"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
react-dropzone@14.2.3:
|
||||
version "14.2.3"
|
||||
resolved "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz"
|
||||
@@ -2279,6 +2329,17 @@ react-dropzone@14.2.3:
|
||||
file-selector "^0.6.0"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
react-grid-layout@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-1.3.4.tgz#4fa819be24a1ba9268aa11b82d63afc4762a32ff"
|
||||
integrity sha512-sB3rNhorW77HUdOjB4JkelZTdJGQKuXLl3gNg+BI8gJkTScspL1myfZzW/EM0dLEn+1eH+xW+wNqk0oIM9o7cw==
|
||||
dependencies:
|
||||
clsx "^1.1.1"
|
||||
lodash.isequal "^4.0.0"
|
||||
prop-types "^15.8.1"
|
||||
react-draggable "^4.0.0"
|
||||
react-resizable "^3.0.4"
|
||||
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||
@@ -2313,6 +2374,14 @@ react-remove-scroll@^2.5.5:
|
||||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-resizable@^3.0.4:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-3.0.5.tgz#362721f2efbd094976f1780ae13f1ad7739786c1"
|
||||
integrity sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==
|
||||
dependencies:
|
||||
prop-types "15.x"
|
||||
react-draggable "^4.0.3"
|
||||
|
||||
react-router-dom@^6.14.2:
|
||||
version "6.14.2"
|
||||
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.2.tgz"
|
||||
|
||||
Reference in New Issue
Block a user