wip
This commit is contained in:
@@ -21,12 +21,14 @@
|
||||
"@blocknote/react": "0.23.2",
|
||||
"@blocknote/xl-docx-exporter": "0.23.2",
|
||||
"@blocknote/xl-pdf-exporter": "0.23.2",
|
||||
"@fontsource/material-icons": "^5.1.1",
|
||||
"@gouvfr-lasuite/integration": "1.0.2",
|
||||
"@hocuspocus/provider": "2.15.2",
|
||||
"@openfun/cunningham-react": "2.9.4",
|
||||
"@react-pdf/renderer": "4.1.6",
|
||||
"@sentry/nextjs": "8.54.0",
|
||||
"@tanstack/react-query": "5.66.0",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.0.4",
|
||||
"crisp-sdk-web": "1.0.25",
|
||||
"docx": "9.1.1",
|
||||
@@ -38,11 +40,13 @@
|
||||
"next": "15.1.6",
|
||||
"posthog-js": "1.215.6",
|
||||
"react": "*",
|
||||
"react-arborist": "3.4.0",
|
||||
"react-aria-components": "1.6.0",
|
||||
"react-dom": "*",
|
||||
"react-i18next": "15.4.0",
|
||||
"react-intersection-observer": "9.15.1",
|
||||
"react-select": "5.10.0",
|
||||
"sass": "1.83.4",
|
||||
"styled-components": "6.1.15",
|
||||
"use-debounce": "10.0.4",
|
||||
"y-protocols": "1.0.6",
|
||||
@@ -74,6 +78,7 @@
|
||||
"stylelint-config-standard": "37.0.0",
|
||||
"stylelint-prettier": "5.0.3",
|
||||
"typescript": "*",
|
||||
"use-resize-observer": "9.1.0",
|
||||
"webpack": "5.97.1",
|
||||
"workbox-webpack-plugin": "7.1.0"
|
||||
}
|
||||
|
||||
@@ -64,6 +64,14 @@ export const DropButton = ({
|
||||
onOpenChange?.(isOpen);
|
||||
};
|
||||
|
||||
const props = {
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
onOpenChangeHandler(!isLocalOpen);
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledButton
|
||||
@@ -71,6 +79,8 @@ export const DropButton = ({
|
||||
onPress={() => onOpenChangeHandler(true)}
|
||||
aria-label={label}
|
||||
$css={buttonCss}
|
||||
{...props}
|
||||
|
||||
>
|
||||
{button}
|
||||
</StyledButton>
|
||||
|
||||
@@ -23,6 +23,7 @@ export type DropdownMenuProps = {
|
||||
buttonCss?: BoxProps['$css'];
|
||||
disabled?: boolean;
|
||||
topMessage?: string;
|
||||
afterOpenChange?: (isOpen: boolean) => void;
|
||||
};
|
||||
|
||||
export const DropdownMenu = ({
|
||||
@@ -34,6 +35,7 @@ export const DropdownMenu = ({
|
||||
buttonCss,
|
||||
label,
|
||||
topMessage,
|
||||
afterOpenChange,
|
||||
}: PropsWithChildren<DropdownMenuProps>) => {
|
||||
const theme = useCunninghamTheme();
|
||||
const spacings = theme.spacingsTokens();
|
||||
@@ -43,6 +45,7 @@ export const DropdownMenu = ({
|
||||
|
||||
const onOpenChange = (isOpen: boolean) => {
|
||||
setIsOpen(isOpen);
|
||||
afterOpenChange?.(isOpen);
|
||||
};
|
||||
|
||||
if (disabled) {
|
||||
|
||||
@@ -5,10 +5,19 @@ import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
type IconProps = TextType & {
|
||||
iconName: string;
|
||||
isFilled?: boolean;
|
||||
};
|
||||
export const Icon = ({ iconName, ...textProps }: IconProps) => {
|
||||
export const Icon = ({ iconName, isFilled, ...textProps }: IconProps) => {
|
||||
return (
|
||||
<Text $isMaterialIcon {...textProps}>
|
||||
<Text
|
||||
$isMaterialIcon={!isFilled}
|
||||
{...textProps}
|
||||
className={
|
||||
isFilled
|
||||
? `material-icons-filled ${textProps.className}`
|
||||
: textProps.className
|
||||
}
|
||||
>
|
||||
{iconName}
|
||||
</Text>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import styles from './loader.module.scss';
|
||||
|
||||
interface LoaderProps {
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl';
|
||||
}
|
||||
|
||||
export const Loader = ({ size = 'sm' }: LoaderProps) => {
|
||||
return <div className={[styles.loader, styles[size]].join(' ')} />;
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
.loader {
|
||||
border-radius: 50%;
|
||||
background:
|
||||
radial-gradient(farthest-side, #cecece 94%, #0000) top/3.8px 3.8px no-repeat,
|
||||
conic-gradient(#0000 30%, #cecece);
|
||||
-webkit-mask: radial-gradient(
|
||||
farthest-side,
|
||||
#0000 calc(100% - 3.8px),
|
||||
#000 0
|
||||
);
|
||||
animation: spinner-c7wet2 1s infinite linear;
|
||||
&.sm {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
&.md {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&.lg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.xl {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
}
|
||||
|
||||
@keyframes spinner-c7wet2 {
|
||||
100% {
|
||||
transform: rotate(1turn);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
import { clsx } from 'clsx';
|
||||
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
CursorProps,
|
||||
MoveHandler,
|
||||
NodeApi,
|
||||
NodeRendererProps,
|
||||
Tree,
|
||||
} from 'react-arborist';
|
||||
|
||||
import {
|
||||
BaseType,
|
||||
TreeViewDataType,
|
||||
TreeViewMoveModeEnum,
|
||||
TreeViewMoveResult,
|
||||
} from '@/features/docs/doc-tree/types/tree';
|
||||
|
||||
import { Box } from '../../Box';
|
||||
import { Icon } from '../../Icon';
|
||||
import { Loader } from '../loader/Loader';
|
||||
|
||||
import styles from './treeview.module.scss';
|
||||
|
||||
export type TreeViewProps<T> = {
|
||||
treeData: TreeViewDataType<T>[];
|
||||
width?: number | string;
|
||||
selectedNodeId?: string;
|
||||
rootNodeId: string;
|
||||
renderNode: (
|
||||
props: NodeRendererProps<TreeViewDataType<T>>,
|
||||
) => React.ReactNode;
|
||||
afterMove?: (
|
||||
result: TreeViewMoveResult,
|
||||
newTreeData: TreeViewDataType<T>[],
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const TreeView = <T,>({
|
||||
treeData,
|
||||
width,
|
||||
rootNodeId,
|
||||
renderNode,
|
||||
afterMove,
|
||||
selectedNodeId,
|
||||
}: TreeViewProps<T>) => {
|
||||
const onMove3 = (args: {
|
||||
dragIds: string[];
|
||||
dragNodes: NodeApi<BaseType<T>>[];
|
||||
parentId: string | null;
|
||||
parentNode: NodeApi<BaseType<T>> | null;
|
||||
index: number;
|
||||
}): TreeViewMoveResult | null => {
|
||||
const newData = JSON.parse(
|
||||
JSON.stringify(treeData),
|
||||
) as TreeViewDataType<T>[];
|
||||
|
||||
const sourceNodeId = args.dragNodes[0].data.id;
|
||||
const sourceNode = args.dragNodes[0].data;
|
||||
const oldParentId = sourceNode.parentId ?? rootNodeId;
|
||||
const newIndex = args.index;
|
||||
const targetNodeId = args.parentId ?? rootNodeId;
|
||||
|
||||
const children = args.parentId
|
||||
? (args.parentNode?.children ?? [])
|
||||
: newData;
|
||||
|
||||
let result: TreeViewMoveResult | null = null;
|
||||
|
||||
if (newIndex === 0) {
|
||||
result = {
|
||||
targetNodeId: targetNodeId ?? rootNodeId,
|
||||
mode: TreeViewMoveModeEnum.FIRST_CHILD,
|
||||
sourceNodeId,
|
||||
oldParentId,
|
||||
};
|
||||
}
|
||||
if (newIndex === children.length) {
|
||||
result = {
|
||||
targetNodeId: targetNodeId ?? rootNodeId,
|
||||
mode: TreeViewMoveModeEnum.LAST_CHILD,
|
||||
sourceNodeId,
|
||||
oldParentId,
|
||||
};
|
||||
}
|
||||
|
||||
const siblingIndex = newIndex - 1;
|
||||
const sibling = children[siblingIndex];
|
||||
|
||||
if (sibling) {
|
||||
result = {
|
||||
targetNodeId: sibling.id,
|
||||
mode: TreeViewMoveModeEnum.RIGHT,
|
||||
sourceNodeId,
|
||||
oldParentId,
|
||||
};
|
||||
}
|
||||
|
||||
const nextSiblingIndex = newIndex + 1;
|
||||
const nextSibling = children[nextSiblingIndex];
|
||||
if (nextSibling) {
|
||||
result = {
|
||||
targetNodeId: nextSibling.id,
|
||||
mode: TreeViewMoveModeEnum.LEFT,
|
||||
sourceNodeId,
|
||||
oldParentId,
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const onMove = (args: {
|
||||
dragIds: string[];
|
||||
dragNodes: NodeApi<BaseType<T>>[];
|
||||
parentId: string | null;
|
||||
parentNode: NodeApi<BaseType<T>> | null;
|
||||
index: number;
|
||||
}) => {
|
||||
// Création d'une copie profonde pour éviter les mutations directes
|
||||
const newData = JSON.parse(
|
||||
JSON.stringify(treeData),
|
||||
) as TreeViewDataType<T>[];
|
||||
const draggedId = args.dragIds[0];
|
||||
|
||||
// Fonction helper pour trouver et supprimer un nœud dans l'arbre
|
||||
const findAndRemoveNode = (
|
||||
items: TreeViewDataType<T>[],
|
||||
parentId?: string,
|
||||
): {
|
||||
currentIndex: number;
|
||||
newIndex: number;
|
||||
parentId?: string;
|
||||
draggedNode: TreeViewDataType<T>;
|
||||
} | null => {
|
||||
items.forEach((item, index) => {
|
||||
if (item.id === draggedId) {
|
||||
return {
|
||||
currentIndex: index,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].id === draggedId) {
|
||||
const currentIndex = i;
|
||||
let newIndex = args.index;
|
||||
if (currentIndex < newIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
return {
|
||||
currentIndex: i,
|
||||
parentId,
|
||||
newIndex,
|
||||
draggedNode: items.splice(i, 1)[0],
|
||||
};
|
||||
}
|
||||
if (items[i].children?.length) {
|
||||
const found = findAndRemoveNode(
|
||||
items[i]?.children ?? [],
|
||||
items[i].id,
|
||||
);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Trouver et supprimer le nœud déplacé
|
||||
const r = findAndRemoveNode(newData);
|
||||
const draggedNode = r?.draggedNode;
|
||||
const currentIndex = r?.currentIndex ?? -1;
|
||||
const newIndex = r?.newIndex ?? -1;
|
||||
if (!draggedNode || currentIndex < 0 || newIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cas 1: Déplacement à la racine
|
||||
if (!args.parentNode) {
|
||||
draggedNode.parentId = rootNodeId;
|
||||
newData.splice(newIndex, 0, draggedNode);
|
||||
}
|
||||
// Cas 2: Déplacement dans un dossier
|
||||
else {
|
||||
const targetParent = args.parentNode.data;
|
||||
draggedNode.parentId = targetParent.id;
|
||||
const findParentAndInsert = (items: TreeViewDataType<T>[]) => {
|
||||
for (const item of items) {
|
||||
if (item.id === targetParent.id) {
|
||||
item.children = item.children || [];
|
||||
item.children.splice(
|
||||
r.parentId === targetParent.id ? r.newIndex : args.index,
|
||||
0,
|
||||
draggedNode,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
if (item.children?.length) {
|
||||
if (findParentAndInsert(item.children)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
findParentAndInsert(newData);
|
||||
}
|
||||
|
||||
const moveResult = onMove3(args);
|
||||
if (moveResult) {
|
||||
afterMove?.(moveResult, newData);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Tree
|
||||
data={treeData}
|
||||
openByDefault={false}
|
||||
height={1000}
|
||||
indent={20}
|
||||
width={width}
|
||||
selection={selectedNodeId}
|
||||
disableEdit={true}
|
||||
rowHeight={32}
|
||||
overscanCount={20}
|
||||
padding={25}
|
||||
renderCursor={Cursor}
|
||||
onMove={onMove as MoveHandler<TreeViewDataType<T>>}
|
||||
>
|
||||
{(props) => renderNode(props)}
|
||||
</Tree>
|
||||
);
|
||||
};
|
||||
|
||||
function Cursor({ top, left }: CursorProps) {
|
||||
return (
|
||||
<div
|
||||
className={styles.cursor}
|
||||
style={{
|
||||
top,
|
||||
left: left + 10,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
export type TreeViewNodeProps<T> = NodeRendererProps<TreeViewDataType<T>> & {
|
||||
children: ReactNode;
|
||||
onClick?: () => void;
|
||||
loadChildren?: (node?: TreeViewDataType<T>) => Promise<TreeViewDataType<T>[]>;
|
||||
};
|
||||
|
||||
export const TreeViewNode = <T,>({
|
||||
children,
|
||||
onClick,
|
||||
node,
|
||||
dragHandle,
|
||||
style,
|
||||
loadChildren,
|
||||
}: TreeViewNodeProps<T>) => {
|
||||
/* This node instance can do many things. See the API reference. */
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const hasChildren =
|
||||
(node.data.childrenCount !== undefined && node.data.childrenCount > 0) ||
|
||||
(node.data.children?.length ?? 0) > 0;
|
||||
|
||||
const isLeaf = node.isLeaf || !hasChildren;
|
||||
|
||||
const hasLoadedChildren = node.children?.length ?? 0 > 0;
|
||||
|
||||
const handleClick = useCallback(async () => {
|
||||
if (isLeaf) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasLoadedChildren) {
|
||||
node.toggle();
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
await loadChildren?.(node.data);
|
||||
setIsLoading(false);
|
||||
node.open();
|
||||
}, [hasLoadedChildren, loadChildren, node, isLeaf]);
|
||||
|
||||
useEffect(() => {
|
||||
if (node.willReceiveDrop && !node.isOpen) {
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
void handleClick();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
if (timeoutRef.current && !node.willReceiveDrop) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
}, [node, handleClick]);
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
onKeyDown={onClick}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={clsx(styles.node, {
|
||||
[styles.willReceiveDrop]: node.willReceiveDrop,
|
||||
[styles.selected]: node.isSelected,
|
||||
toto: true,
|
||||
})}
|
||||
style={{
|
||||
...style,
|
||||
}}
|
||||
ref={dragHandle}
|
||||
>
|
||||
{isLeaf ? (
|
||||
<Box $padding={{ left: '16px' }} />
|
||||
) : (
|
||||
<>
|
||||
{isLoading ? (
|
||||
<Box $padding={{ horizontal: '4px' }}>
|
||||
<Loader />
|
||||
</Box>
|
||||
) : (
|
||||
<Icon
|
||||
onClick={() => void handleClick()}
|
||||
$variation="500"
|
||||
$size="16px"
|
||||
iconName={
|
||||
node.isOpen ? 'keyboard_arrow_down' : 'keyboard_arrow_right'
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,157 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { Doc, getDoc } from '@/features/docs';
|
||||
import { TreeViewDataType } from '@/features/docs/doc-tree/types/tree';
|
||||
|
||||
interface TreeStore<T> {
|
||||
treeData: TreeViewDataType<T>[];
|
||||
selectedNode: TreeViewDataType<T> | null;
|
||||
setSelectedNode: (node: TreeViewDataType<T> | null) => void;
|
||||
setTreeData: (data: TreeViewDataType<T>[]) => void;
|
||||
updateNode: (nodeId: string, newData: Partial<TreeViewDataType<T>>) => void;
|
||||
addRootNode: (node: TreeViewDataType<T>) => void;
|
||||
removeNode: (nodeId: string) => void;
|
||||
addChildNode: (parentId: string, newNode: TreeViewDataType<T>) => void;
|
||||
refreshNode: (nodeId: string) => void;
|
||||
findNode: (nodeId: string) => TreeViewDataType<T> | null;
|
||||
}
|
||||
|
||||
export const createTreeStore = <T>(
|
||||
refreshCallback?: (id: string) => Promise<Partial<TreeViewDataType<T>>>,
|
||||
) =>
|
||||
create<TreeStore<T>>((set, get) => ({
|
||||
treeData: [],
|
||||
selectedNode: null,
|
||||
setSelectedNode: (node) => {
|
||||
set({ selectedNode: node });
|
||||
},
|
||||
setTreeData: (data) => {
|
||||
set({ treeData: data });
|
||||
},
|
||||
refreshNode: (nodeId) => {
|
||||
set((state) => {
|
||||
const node = state.findNode(nodeId);
|
||||
if (!node) {
|
||||
return state;
|
||||
}
|
||||
refreshCallback?.(nodeId)
|
||||
.then((data) => {
|
||||
state.updateNode(nodeId, { ...node, ...data });
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
return state;
|
||||
});
|
||||
},
|
||||
updateNode: (nodeId, newData) => {
|
||||
set((state) => {
|
||||
const updateNodeInTree = (
|
||||
nodes: TreeViewDataType<T>[],
|
||||
): TreeViewDataType<T>[] => {
|
||||
return nodes.map((node) => {
|
||||
if (node.id === nodeId) {
|
||||
return { ...node, ...newData };
|
||||
}
|
||||
if (node.children) {
|
||||
return {
|
||||
...node,
|
||||
children: updateNodeInTree(node.children),
|
||||
};
|
||||
}
|
||||
return node;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
treeData: updateNodeInTree(state.treeData),
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
addRootNode: (node) => {
|
||||
set((state) => ({
|
||||
treeData: [...state.treeData, node],
|
||||
}));
|
||||
},
|
||||
|
||||
removeNode: (nodeId) => {
|
||||
set((state) => {
|
||||
const removeNodeFromTree = (
|
||||
nodes: TreeViewDataType<T>[],
|
||||
): TreeViewDataType<T>[] => {
|
||||
const filteredNodes = nodes.filter((node) => node.id !== nodeId);
|
||||
|
||||
return filteredNodes.map((node) => {
|
||||
if (node.children) {
|
||||
return {
|
||||
...node,
|
||||
children: removeNodeFromTree(node.children),
|
||||
};
|
||||
}
|
||||
return node;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
treeData: removeNodeFromTree(state.treeData),
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
addChildNode: (parentId, newNode) => {
|
||||
set((state) => {
|
||||
const addChildToNode = (
|
||||
nodes: TreeViewDataType<T>[],
|
||||
): TreeViewDataType<T>[] => {
|
||||
return nodes.map((node) => {
|
||||
if (node.id === parentId) {
|
||||
return {
|
||||
...node,
|
||||
children: [...(node.children || []), newNode],
|
||||
};
|
||||
}
|
||||
if (node.children) {
|
||||
return {
|
||||
...node,
|
||||
children: addChildToNode(node.children),
|
||||
};
|
||||
}
|
||||
return node;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
treeData: addChildToNode(state.treeData),
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
findNode: (nodeId) => {
|
||||
const findNodeInTree = (
|
||||
nodes: TreeViewDataType<T>[],
|
||||
): TreeViewDataType<T> | null => {
|
||||
for (const node of nodes) {
|
||||
if (node.id === nodeId) {
|
||||
return node;
|
||||
}
|
||||
if (node.children) {
|
||||
const found = findNodeInTree(node.children);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return findNodeInTree(get().treeData);
|
||||
},
|
||||
}));
|
||||
|
||||
// Créer une instance du store
|
||||
// export const useTreeStore = createTreeStore();
|
||||
export const useTreeStore = createTreeStore<Doc>(async (docId) => {
|
||||
const doc = await getDoc({ id: docId });
|
||||
return { ...doc, childrenCount: doc.numchild };
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
.container {
|
||||
[role='treeitem'] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.node {
|
||||
width: 100%;
|
||||
// padding-left: 0px !important;
|
||||
// margin-left: 180px;
|
||||
// min-width: 300px;
|
||||
height: calc(100% - 2px);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
border-radius: 4px;
|
||||
border: 1.5px solid rgba(0, 0, 0, 0);
|
||||
cursor: pointer;
|
||||
|
||||
padding: var(--c--theme--spacings--4xs) 0;
|
||||
gap: var(--c--theme--spacings--3xs);
|
||||
|
||||
&:not(.willReceiveDrop, .selected):hover {
|
||||
background-color: var(--c--theme--colors--greyscale-100);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: var(--c--theme--colors--greyscale-100);
|
||||
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&.willReceiveDrop {
|
||||
background-color: var(--c--theme--colors--primary-100);
|
||||
border: 1.5px solid var(--c--theme--colors--primary-500);
|
||||
}
|
||||
}
|
||||
|
||||
.cursor {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
border-top: 2px solid var(--c--theme--colors--primary-500);
|
||||
}
|
||||
@@ -41,7 +41,10 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<CunninghamProvider theme={theme}>
|
||||
<ConfigProvider>
|
||||
<Auth>{children}</Auth>
|
||||
<Auth>
|
||||
{children}
|
||||
<div id="modals" />
|
||||
</Auth>
|
||||
</ConfigProvider>
|
||||
</CunninghamProvider>
|
||||
</QueryClientProvider>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, Text } from '@/components';
|
||||
import { useTreeStore } from '@/components/common/tree/treeStore';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import {
|
||||
Doc,
|
||||
@@ -52,6 +53,8 @@ export const DocTitleText = ({ title }: DocTitleTextProps) => {
|
||||
|
||||
const DocTitleInput = ({ doc }: DocTitleProps) => {
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { updateNode, setSelectedNode } = useTreeStore();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
const [titleDisplay, setTitleDisplay] = useState(doc.title);
|
||||
@@ -64,7 +67,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
|
||||
listInvalideQueries: [KEY_DOC, KEY_LIST_DOC],
|
||||
onSuccess(data) {
|
||||
toast(t('Document title updated successfully'), VariantType.SUCCESS);
|
||||
|
||||
updateNode(doc.id, { title: data.title });
|
||||
// Broadcast to every user connected to the document
|
||||
broadcast(`${KEY_DOC}-${data.id}`);
|
||||
},
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
import { Button, Modal, ModalSize } from '@openfun/cunningham-react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Text } from '@/components';
|
||||
|
||||
import { Doc } from '../types';
|
||||
|
||||
interface ModalRenameDocProps {
|
||||
onClose: () => void;
|
||||
doc: Doc;
|
||||
}
|
||||
|
||||
export const ModalRenameDoc = ({ onClose, doc }: ModalRenameDocProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [title, setTitle] = useState(doc.title);
|
||||
return (
|
||||
<Modal
|
||||
closeOnClickOutside
|
||||
title={
|
||||
<Text $size="h6" $margin={{ all: '0' }} $align="flex-start">
|
||||
{t('Rename')}
|
||||
</Text>
|
||||
}
|
||||
isOpen
|
||||
onClose={onClose}
|
||||
size={ModalSize.SMALL}
|
||||
rightActions={
|
||||
<>
|
||||
<Button
|
||||
aria-label={t('Close the modal')}
|
||||
color="secondary"
|
||||
fullWidth
|
||||
onClick={() => onClose()}
|
||||
>
|
||||
{t('Cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
aria-label={t('Confirm deletion')}
|
||||
fullWidth
|
||||
onClick={() => console.log('rename', title)}
|
||||
>
|
||||
{t('Delete')}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Box $padding={{ top: 'base' }}>
|
||||
<input
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
defaultValue={title}
|
||||
// label={t('Nom du document')}
|
||||
onChange={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
setTitle(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -45,6 +45,7 @@ export interface Doc {
|
||||
nb_accesses: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
numchild: number;
|
||||
abilities: {
|
||||
accesses_manage: boolean;
|
||||
accesses_view: boolean;
|
||||
|
||||
@@ -57,6 +57,7 @@ export const DocShareModal = ({ doc, onClose }: Props) => {
|
||||
const canShare = doc.abilities.accesses_manage;
|
||||
const canViewAccesses = doc.abilities.accesses_view;
|
||||
const showMemberSection = inputValue === '' && selectedUsers.length === 0;
|
||||
|
||||
const showFooter = selectedUsers.length === 0 && !inputValue;
|
||||
|
||||
const onSelect = (user: User) => {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
|
||||
import { Doc, KEY_LIST_DOC } from '../../doc-management';
|
||||
|
||||
export type CreateDocParam = Pick<Doc, 'title'> & {
|
||||
parentId: string;
|
||||
};
|
||||
|
||||
export const createDocChildren = async ({
|
||||
title,
|
||||
parentId,
|
||||
}: CreateDocParam): Promise<Doc> => {
|
||||
const response = await fetchAPI(`documents/${parentId}/children/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError('Failed to create the doc', await errorCauses(response));
|
||||
}
|
||||
|
||||
return response.json() as Promise<Doc>;
|
||||
};
|
||||
|
||||
interface CreateDocProps {
|
||||
onSuccess: (data: Doc) => void;
|
||||
}
|
||||
|
||||
export function useCreateChildrenDoc({ onSuccess }: CreateDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Doc, APIError, CreateDocParam>({
|
||||
mutationFn: createDocChildren,
|
||||
onSuccess: (data) => {
|
||||
void queryClient.resetQueries({
|
||||
queryKey: [KEY_LIST_DOC],
|
||||
});
|
||||
onSuccess(data);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { UseQueryOptions, useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI, useAPIInfiniteQuery } from '@/api';
|
||||
|
||||
import { DocsResponse } from '../../doc-management';
|
||||
|
||||
export type DocsChildrenParams = {
|
||||
docId: string;
|
||||
page: number;
|
||||
page_size?: number;
|
||||
};
|
||||
|
||||
export const getDocChildren = async (
|
||||
params: DocsChildrenParams,
|
||||
): Promise<DocsResponse> => {
|
||||
const { docId, page, page_size } = params;
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
if (page) {
|
||||
searchParams.set('page', page.toString());
|
||||
}
|
||||
if (page_size) {
|
||||
searchParams.set('page_size', page_size.toString());
|
||||
}
|
||||
|
||||
const response = await fetchAPI(
|
||||
`documents/${docId}/children/?${searchParams.toString()}`,
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
'Failed to get the doc children',
|
||||
await errorCauses(response),
|
||||
);
|
||||
}
|
||||
|
||||
return response.json() as Promise<DocsResponse>;
|
||||
};
|
||||
|
||||
export const KEY_LIST_DOC_CHILDREN = 'doc-children';
|
||||
|
||||
export function useDocChildren(
|
||||
params: DocsChildrenParams,
|
||||
queryConfig?: Omit<
|
||||
UseQueryOptions<DocsResponse, APIError, DocsResponse>,
|
||||
'queryKey' | 'queryFn'
|
||||
>,
|
||||
) {
|
||||
return useQuery<DocsResponse, APIError, DocsResponse>({
|
||||
queryKey: [KEY_LIST_DOC_CHILDREN, params],
|
||||
queryFn: () => getDocChildren(params),
|
||||
...queryConfig,
|
||||
});
|
||||
}
|
||||
|
||||
export const useInfiniteDocChildren = (params: DocsChildrenParams) => {
|
||||
return useAPIInfiniteQuery(KEY_LIST_DOC_CHILDREN, getDocChildren, params);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.40918 4.69434C5.28613 4.69434 5.18359 4.65332 5.10156 4.57129C5.02409 4.48926 4.98535 4.389 4.98535 4.27051C4.98535 4.15202 5.02409 4.05404 5.10156 3.97656C5.18359 3.89453 5.28613 3.85352 5.40918 3.85352H10.5977C10.7161 3.85352 10.8141 3.89453 10.8916 3.97656C10.9736 4.05404 11.0146 4.15202 11.0146 4.27051C11.0146 4.389 10.9736 4.48926 10.8916 4.57129C10.8141 4.65332 10.7161 4.69434 10.5977 4.69434H5.40918ZM5.40918 7.08008C5.28613 7.08008 5.18359 7.03906 5.10156 6.95703C5.02409 6.875 4.98535 6.77474 4.98535 6.65625C4.98535 6.53776 5.02409 6.43978 5.10156 6.3623C5.18359 6.28027 5.28613 6.23926 5.40918 6.23926H10.5977C10.7161 6.23926 10.8141 6.28027 10.8916 6.3623C10.9736 6.43978 11.0146 6.53776 11.0146 6.65625C11.0146 6.77474 10.9736 6.875 10.8916 6.95703C10.8141 7.03906 10.7161 7.08008 10.5977 7.08008H5.40918ZM5.40918 9.46582C5.28613 9.46582 5.18359 9.42708 5.10156 9.34961C5.02409 9.26758 4.98535 9.1696 4.98535 9.05566C4.98535 8.93262 5.02409 8.83008 5.10156 8.74805C5.18359 8.66602 5.28613 8.625 5.40918 8.625H7.86328C7.98633 8.625 8.08659 8.66602 8.16406 8.74805C8.24609 8.83008 8.28711 8.93262 8.28711 9.05566C8.28711 9.1696 8.24609 9.26758 8.16406 9.34961C8.08659 9.42708 7.98633 9.46582 7.86328 9.46582H5.40918ZM2.25098 13.2529V2.88281C2.25098 2.17188 2.42643 1.63639 2.77734 1.27637C3.13281 0.916341 3.66374 0.736328 4.37012 0.736328H11.6299C12.3363 0.736328 12.8649 0.916341 13.2158 1.27637C13.5713 1.63639 13.749 2.17188 13.749 2.88281V13.2529C13.749 13.9684 13.5713 14.5039 13.2158 14.8594C12.8649 15.2148 12.3363 15.3926 11.6299 15.3926H4.37012C3.66374 15.3926 3.13281 15.2148 2.77734 14.8594C2.42643 14.5039 2.25098 13.9684 2.25098 13.2529ZM3.35156 13.2324C3.35156 13.5742 3.44043 13.8363 3.61816 14.0186C3.80046 14.2008 4.06934 14.292 4.4248 14.292H11.5752C11.9307 14.292 12.1973 14.2008 12.375 14.0186C12.5573 13.8363 12.6484 13.5742 12.6484 13.2324V2.90332C12.6484 2.56152 12.5573 2.29948 12.375 2.11719C12.1973 1.93034 11.9307 1.83691 11.5752 1.83691H4.4248C4.06934 1.83691 3.80046 1.93034 3.61816 2.11719C3.44043 2.29948 3.35156 2.56152 3.35156 2.90332V13.2324Z" fill="#8585F6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 356 B |
@@ -0,0 +1,127 @@
|
||||
import { useEffect } from 'react';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { fetchAPI } from '@/api';
|
||||
import { Box, SeparatedSection, StyledLink } from '@/components';
|
||||
import { TreeView } from '@/components/common/tree/TreeView';
|
||||
import { useTreeStore } from '@/components/common/tree/treeStore';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { Doc, useDoc } from '../../doc-management';
|
||||
import { SimpleDocItem } from '../../docs-grid';
|
||||
import { useInfiniteDocChildren } from '../api/useDocChildren';
|
||||
import { TreeViewDataType, TreeViewMoveResult } from '../types/tree';
|
||||
|
||||
import { DocTreeItem } from './DocTreeItem';
|
||||
|
||||
type Props = {
|
||||
docId: Doc['id'];
|
||||
};
|
||||
|
||||
export type DocTreeDataType = TreeViewDataType<Doc>;
|
||||
export const DocTree = ({ docId }: Props) => {
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const spacing = spacingsTokens();
|
||||
const { data: rootNode } = useDoc({ id: docId });
|
||||
const {
|
||||
selectedNode,
|
||||
setSelectedNode,
|
||||
refreshNode,
|
||||
setTreeData: setTreeDataStore,
|
||||
treeData: treeDataStore,
|
||||
} = useTreeStore();
|
||||
|
||||
const { data, isLoading, isFetching, isRefetching } = useInfiniteDocChildren({
|
||||
docId,
|
||||
page_size: 25,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
const afterMove = async (
|
||||
result: TreeViewMoveResult,
|
||||
newTreeData: TreeViewDataType<Doc>[],
|
||||
) => {
|
||||
const { targetNodeId, mode: position, sourceNodeId, oldParentId } = result;
|
||||
await fetchAPI(`documents/${sourceNodeId}/move/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
target_document_id: targetNodeId,
|
||||
position,
|
||||
}),
|
||||
});
|
||||
|
||||
setTreeDataStore(newTreeData);
|
||||
if (oldParentId) {
|
||||
refreshNode(oldParentId);
|
||||
}
|
||||
refreshNode(targetNodeId);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newChildren = data.pages.flatMap((page) => page.results);
|
||||
const newData: DocTreeDataType[] = newChildren.map((child) => ({
|
||||
...child,
|
||||
childrenCount: child.numchild,
|
||||
children: [],
|
||||
parentId: docId,
|
||||
}));
|
||||
setTreeDataStore(newData);
|
||||
}, [data, setTreeDataStore, docId]);
|
||||
|
||||
const isRootNodeSelected = !selectedNode
|
||||
? true
|
||||
: selectedNode?.id === rootNode?.id;
|
||||
|
||||
if (isLoading || isFetching || isRefetching) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return <div>No data</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SeparatedSection showSeparator={false}>
|
||||
<Box $padding={{ horizontal: 'sm' }}>
|
||||
<Box
|
||||
$css={css`
|
||||
padding: ${spacing['2xs']};
|
||||
border-radius: 4px;
|
||||
background-color: ${isRootNodeSelected
|
||||
? 'var(--c--theme--colors--greyscale-100)'
|
||||
: 'transparent'};
|
||||
`}
|
||||
>
|
||||
{rootNode && (
|
||||
<StyledLink
|
||||
href={`/docs/${rootNode.id}`}
|
||||
onClick={() => {
|
||||
setSelectedNode(rootNode);
|
||||
}}
|
||||
>
|
||||
<SimpleDocItem doc={rootNode} showAccesses={false} />
|
||||
</StyledLink>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</SeparatedSection>
|
||||
<Box $padding={{ all: 'sm' }} $margin={{ top: '-35px' }} $width="100%">
|
||||
<TreeView
|
||||
treeData={treeDataStore}
|
||||
width="100%"
|
||||
selectedNodeId={selectedNode?.id}
|
||||
rootNodeId={docId}
|
||||
renderNode={(props) => <DocTreeItem {...props} />}
|
||||
afterMove={(result, newTreeData) => {
|
||||
void afterMove(result, newTreeData);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,155 @@
|
||||
import { useModal } from '@openfun/cunningham-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { NodeRendererProps } from 'react-arborist';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, BoxButton, DropdownMenu, Icon } from '@/components';
|
||||
import { TreeViewNode } from '@/components/common/tree/TreeView';
|
||||
import { useTreeStore } from '@/components/common/tree/treeStore';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { useLeftPanelStore } from '@/features/left-panel';
|
||||
|
||||
import { ModalRemoveDoc } from '../../doc-management';
|
||||
import { ModalRenameDoc } from '../../doc-management/components/ModalRenameDoc';
|
||||
import { DocShareModal } from '../../doc-share';
|
||||
import { LightDocItem } from '../../docs-grid/components/LightDocItem';
|
||||
import { useCreateChildrenDoc } from '../api/useCreateChildren';
|
||||
import { useDocChildren } from '../api/useDocChildren';
|
||||
import { TreeViewDataType } from '../types/tree';
|
||||
|
||||
import { DocTreeDataType } from './DocTree';
|
||||
|
||||
type DocTreeItemProps = NodeRendererProps<TreeViewDataType<DocTreeDataType>>;
|
||||
|
||||
export const DocTreeItem = ({ node, ...props }: DocTreeItemProps) => {
|
||||
const data = node.data;
|
||||
const deleteModal = useModal();
|
||||
const shareModal = useModal();
|
||||
const renameModal = useModal();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { updateNode, setSelectedNode } = useTreeStore();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { refetch } = useDocChildren(
|
||||
{
|
||||
docId: data.id,
|
||||
page: 1,
|
||||
},
|
||||
{ enabled: false },
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const { togglePanel } = useLeftPanelStore();
|
||||
const { mutate: createChildrenDoc } = useCreateChildrenDoc({
|
||||
onSuccess: (doc) => {
|
||||
const actualChildren = node.data.children ?? [];
|
||||
if (actualChildren.length === 0) {
|
||||
loadChildren()
|
||||
.then(() => {
|
||||
node.open();
|
||||
router.push(`/docs/${doc.id}`);
|
||||
togglePanel();
|
||||
})
|
||||
.catch(console.error);
|
||||
} else {
|
||||
updateNode(node.id, {
|
||||
...node.data,
|
||||
children: [...actualChildren, doc],
|
||||
});
|
||||
node.open();
|
||||
router.push(`/docs/${doc.id}`);
|
||||
togglePanel();
|
||||
}
|
||||
setSelectedNode(doc);
|
||||
},
|
||||
});
|
||||
const spacing = spacingsTokens();
|
||||
|
||||
const loadChildren = async () => {
|
||||
const data = await refetch();
|
||||
console.log(data, node);
|
||||
const childs = data.data?.results ?? [];
|
||||
const newChilds: TreeViewDataType<DocTreeDataType>[] = childs.map(
|
||||
(child) => ({
|
||||
...child,
|
||||
childrenCount: child.numchild,
|
||||
children: [],
|
||||
parentId: node.id,
|
||||
}),
|
||||
);
|
||||
node.data.children = newChilds;
|
||||
updateNode(node.id, { ...node.data, children: newChilds });
|
||||
return newChilds;
|
||||
};
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: t('Rename'),
|
||||
icon: 'edit',
|
||||
callback: renameModal.open,
|
||||
},
|
||||
{
|
||||
label: t('Share'),
|
||||
icon: 'group',
|
||||
callback: shareModal.open,
|
||||
},
|
||||
{
|
||||
label: t('Delete'),
|
||||
icon: 'delete',
|
||||
callback: deleteModal.open,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<>
|
||||
<TreeViewNode
|
||||
onClick={() => router.push(`/docs/${node.data.id}`)}
|
||||
node={node}
|
||||
{...props}
|
||||
loadChildren={loadChildren}
|
||||
>
|
||||
<LightDocItem
|
||||
showActions={isOpen}
|
||||
doc={node.data}
|
||||
rightContent={
|
||||
<Box $direction="row" $gap={spacing['xs']} $align="center">
|
||||
<DropdownMenu options={options} afterOpenChange={setIsOpen}>
|
||||
<Icon iconName="more_horiz" $theme="primary" $variation="600" />
|
||||
</DropdownMenu>
|
||||
<BoxButton
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
createChildrenDoc({
|
||||
title: t('Untitled page'),
|
||||
parentId: node.id,
|
||||
});
|
||||
}}
|
||||
color="primary-text"
|
||||
>
|
||||
<Icon
|
||||
$variation="800"
|
||||
$theme="primary"
|
||||
isFilled
|
||||
iconName="add_box"
|
||||
/>
|
||||
</BoxButton>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</TreeViewNode>
|
||||
{deleteModal.isOpen && (
|
||||
<ModalRemoveDoc onClose={deleteModal.onClose} doc={node.data} />
|
||||
)}
|
||||
{shareModal.isOpen && (
|
||||
<DocShareModal doc={node.data} onClose={shareModal.close} />
|
||||
)}
|
||||
{renameModal.isOpen &&
|
||||
createPortal(
|
||||
<ModalRenameDoc onClose={renameModal.onClose} doc={node.data} />,
|
||||
document.getElementById('modals') as HTMLElement,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { Doc } from '@/features/docs/doc-management';
|
||||
|
||||
export interface DocRootTreeStore {
|
||||
rootId?: Doc['id'];
|
||||
setRootId: (id?: Doc['id']) => void;
|
||||
}
|
||||
|
||||
export const useDocRootTreeStore = create<DocRootTreeStore>((set) => ({
|
||||
rootId: undefined,
|
||||
setRootId: (id?: string) => {
|
||||
set({ rootId: id });
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,22 @@
|
||||
export type BaseType<T> = T & {
|
||||
id: string;
|
||||
childrenCount?: number;
|
||||
parentId?: string;
|
||||
children?: BaseType<T>[];
|
||||
};
|
||||
|
||||
export type TreeViewDataType<T> = BaseType<T>;
|
||||
|
||||
export enum TreeViewMoveModeEnum {
|
||||
FIRST_CHILD = 'first-child',
|
||||
LAST_CHILD = 'last-child',
|
||||
LEFT = 'left',
|
||||
RIGHT = 'right',
|
||||
}
|
||||
|
||||
export type TreeViewMoveResult = {
|
||||
targetNodeId: string;
|
||||
mode: TreeViewMoveModeEnum;
|
||||
sourceNodeId: string;
|
||||
oldParentId?: string;
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.40918 4.69434C5.28613 4.69434 5.18359 4.65332 5.10156 4.57129C5.02409 4.48926 4.98535 4.389 4.98535 4.27051C4.98535 4.15202 5.02409 4.05404 5.10156 3.97656C5.18359 3.89453 5.28613 3.85352 5.40918 3.85352H10.5977C10.7161 3.85352 10.8141 3.89453 10.8916 3.97656C10.9736 4.05404 11.0146 4.15202 11.0146 4.27051C11.0146 4.389 10.9736 4.48926 10.8916 4.57129C10.8141 4.65332 10.7161 4.69434 10.5977 4.69434H5.40918ZM5.40918 7.08008C5.28613 7.08008 5.18359 7.03906 5.10156 6.95703C5.02409 6.875 4.98535 6.77474 4.98535 6.65625C4.98535 6.53776 5.02409 6.43978 5.10156 6.3623C5.18359 6.28027 5.28613 6.23926 5.40918 6.23926H10.5977C10.7161 6.23926 10.8141 6.28027 10.8916 6.3623C10.9736 6.43978 11.0146 6.53776 11.0146 6.65625C11.0146 6.77474 10.9736 6.875 10.8916 6.95703C10.8141 7.03906 10.7161 7.08008 10.5977 7.08008H5.40918ZM5.40918 9.46582C5.28613 9.46582 5.18359 9.42708 5.10156 9.34961C5.02409 9.26758 4.98535 9.1696 4.98535 9.05566C4.98535 8.93262 5.02409 8.83008 5.10156 8.74805C5.18359 8.66602 5.28613 8.625 5.40918 8.625H7.86328C7.98633 8.625 8.08659 8.66602 8.16406 8.74805C8.24609 8.83008 8.28711 8.93262 8.28711 9.05566C8.28711 9.1696 8.24609 9.26758 8.16406 9.34961C8.08659 9.42708 7.98633 9.46582 7.86328 9.46582H5.40918ZM2.25098 13.2529V2.88281C2.25098 2.17188 2.42643 1.63639 2.77734 1.27637C3.13281 0.916341 3.66374 0.736328 4.37012 0.736328H11.6299C12.3363 0.736328 12.8649 0.916341 13.2158 1.27637C13.5713 1.63639 13.749 2.17188 13.749 2.88281V13.2529C13.749 13.9684 13.5713 14.5039 13.2158 14.8594C12.8649 15.2148 12.3363 15.3926 11.6299 15.3926H4.37012C3.66374 15.3926 3.13281 15.2148 2.77734 14.8594C2.42643 14.5039 2.25098 13.9684 2.25098 13.2529ZM3.35156 13.2324C3.35156 13.5742 3.44043 13.8363 3.61816 14.0186C3.80046 14.2008 4.06934 14.292 4.4248 14.292H11.5752C11.9307 14.292 12.1973 14.2008 12.375 14.0186C12.5573 13.8363 12.6484 13.5742 12.6484 13.2324V2.90332C12.6484 2.56152 12.5573 2.29948 12.375 2.11719C12.1973 1.93034 11.9307 1.83691 11.5752 1.83691H4.4248C4.06934 1.83691 3.80046 1.93034 3.61816 2.11719C3.44043 2.29948 3.35156 2.56152 3.35156 2.90332V13.2324Z" fill="#8585F6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,70 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Doc } from '@/features/docs/doc-management';
|
||||
|
||||
import Logo from './../assets/doc-s.svg';
|
||||
|
||||
const ItemTextCss = css`
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: initial;
|
||||
display: -webkit-box;
|
||||
line-clamp: 1;
|
||||
width: 100%;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
doc: Doc;
|
||||
showActions?: boolean;
|
||||
rightContent?: ReactNode;
|
||||
};
|
||||
|
||||
export const LightDocItem = ({
|
||||
doc,
|
||||
rightContent,
|
||||
showActions = false,
|
||||
}: Props) => {
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const spacing = spacingsTokens();
|
||||
return (
|
||||
<Box
|
||||
$width="100%"
|
||||
$direction="row"
|
||||
$gap={spacing['xs']}
|
||||
$align="center"
|
||||
$css={css`
|
||||
.light-doc-item-actions {
|
||||
display: ${showActions ? 'flex' : 'none'};
|
||||
}
|
||||
&:hover {
|
||||
.light-doc-item-actions {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Box $width={16} $height={16}>
|
||||
<Logo />
|
||||
</Box>
|
||||
|
||||
<Text $css={ItemTextCss} $size="sm">
|
||||
{doc.title}
|
||||
</Text>
|
||||
{rightContent && (
|
||||
<Box
|
||||
$direction="row"
|
||||
$gap={spacing['xs']}
|
||||
$align="center"
|
||||
className="light-doc-item-actions"
|
||||
>
|
||||
{rightContent}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.40918 4.69434C5.28613 4.69434 5.18359 4.65332 5.10156 4.57129C5.02409 4.48926 4.98535 4.389 4.98535 4.27051C4.98535 4.15202 5.02409 4.05404 5.10156 3.97656C5.18359 3.89453 5.28613 3.85352 5.40918 3.85352H10.5977C10.7161 3.85352 10.8141 3.89453 10.8916 3.97656C10.9736 4.05404 11.0146 4.15202 11.0146 4.27051C11.0146 4.389 10.9736 4.48926 10.8916 4.57129C10.8141 4.65332 10.7161 4.69434 10.5977 4.69434H5.40918ZM5.40918 7.08008C5.28613 7.08008 5.18359 7.03906 5.10156 6.95703C5.02409 6.875 4.98535 6.77474 4.98535 6.65625C4.98535 6.53776 5.02409 6.43978 5.10156 6.3623C5.18359 6.28027 5.28613 6.23926 5.40918 6.23926H10.5977C10.7161 6.23926 10.8141 6.28027 10.8916 6.3623C10.9736 6.43978 11.0146 6.53776 11.0146 6.65625C11.0146 6.77474 10.9736 6.875 10.8916 6.95703C10.8141 7.03906 10.7161 7.08008 10.5977 7.08008H5.40918ZM5.40918 9.46582C5.28613 9.46582 5.18359 9.42708 5.10156 9.34961C5.02409 9.26758 4.98535 9.1696 4.98535 9.05566C4.98535 8.93262 5.02409 8.83008 5.10156 8.74805C5.18359 8.66602 5.28613 8.625 5.40918 8.625H7.86328C7.98633 8.625 8.08659 8.66602 8.16406 8.74805C8.24609 8.83008 8.28711 8.93262 8.28711 9.05566C8.28711 9.1696 8.24609 9.26758 8.16406 9.34961C8.08659 9.42708 7.98633 9.46582 7.86328 9.46582H5.40918ZM2.25098 13.2529V2.88281C2.25098 2.17188 2.42643 1.63639 2.77734 1.27637C3.13281 0.916341 3.66374 0.736328 4.37012 0.736328H11.6299C12.3363 0.736328 12.8649 0.916341 13.2158 1.27637C13.5713 1.63639 13.749 2.17188 13.749 2.88281V13.2529C13.749 13.9684 13.5713 14.5039 13.2158 14.8594C12.8649 15.2148 12.3363 15.3926 11.6299 15.3926H4.37012C3.66374 15.3926 3.13281 15.2148 2.77734 14.8594C2.42643 14.5039 2.25098 13.9684 2.25098 13.2529ZM3.35156 13.2324C3.35156 13.5742 3.44043 13.8363 3.61816 14.0186C3.80046 14.2008 4.06934 14.292 4.4248 14.292H11.5752C11.9307 14.292 12.1973 14.2008 12.375 14.0186C12.5573 13.8363 12.6484 13.5742 12.6484 13.2324V2.90332C12.6484 2.56152 12.5573 2.29948 12.375 2.11719C12.1973 1.93034 11.9307 1.83691 11.5752 1.83691H4.4248C4.06934 1.83691 3.80046 1.93034 3.61816 2.11719C3.44043 2.29948 3.35156 2.56152 3.35156 2.90332V13.2324Z" fill="#8585F6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 356 B |
+6
-20
@@ -1,14 +1,12 @@
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, SeparatedSection } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Box } from '@/components';
|
||||
import { useDocStore } from '@/features/docs/doc-management';
|
||||
import { SimpleDocItem } from '@/features/docs/docs-grid';
|
||||
import { DocTree } from '@/features/docs/doc-tree/components/DocTree';
|
||||
import { useDocRootTreeStore } from '@/features/docs/doc-tree/stores/useDocRootTree';
|
||||
|
||||
export const LeftPanelDocContent = () => {
|
||||
const { rootId } = useDocRootTreeStore();
|
||||
const { currentDoc } = useDocStore();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const spacing = spacingsTokens();
|
||||
|
||||
if (!currentDoc) {
|
||||
return null;
|
||||
}
|
||||
@@ -19,19 +17,7 @@ export const LeftPanelDocContent = () => {
|
||||
$width="100%"
|
||||
$css="width: 100%; overflow-y: auto; overflow-x: hidden;"
|
||||
>
|
||||
<SeparatedSection showSeparator={false}>
|
||||
<Box $padding={{ horizontal: 'sm' }}>
|
||||
<Box
|
||||
$css={css`
|
||||
padding: ${spacing['2xs']};
|
||||
border-radius: 4px;
|
||||
background-color: var(--c--theme--colors--greyscale-100);
|
||||
`}
|
||||
>
|
||||
<SimpleDocItem doc={currentDoc} showAccesses={true} />
|
||||
</Box>
|
||||
</Box>
|
||||
</SeparatedSection>
|
||||
{rootId && <DocTree docId={rootId} />}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,22 +4,37 @@ import { useRouter } from 'next/navigation';
|
||||
import { PropsWithChildren } from 'react';
|
||||
|
||||
import { Box, Icon, SeparatedSection } from '@/components';
|
||||
import { useTreeStore } from '@/components/common/tree/treeStore';
|
||||
import { useAuth } from '@/features/auth';
|
||||
import { useCreateDoc } from '@/features/docs/doc-management';
|
||||
import { useCreateDoc, useDocStore } from '@/features/docs/doc-management';
|
||||
import { DocSearchModal } from '@/features/docs/doc-search';
|
||||
import { useCmdK } from '@/hook/useCmdK';
|
||||
import { useCreateChildrenDoc } from '@/features/docs/doc-tree/api/useCreateChildren';
|
||||
|
||||
import { useLeftPanelStore } from '../stores';
|
||||
|
||||
export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
|
||||
type Props = PropsWithChildren<{}>;
|
||||
|
||||
export const LeftPanelHeader = ({ children }: Props) => {
|
||||
const router = useRouter();
|
||||
const { currentDoc } = useDocStore();
|
||||
const treeStore = useTreeStore();
|
||||
|
||||
const searchModal = useModal();
|
||||
const { authenticated } = useAuth();
|
||||
useCmdK(searchModal.open);
|
||||
const { togglePanel } = useLeftPanelStore();
|
||||
|
||||
const { mutate: createDoc } = useCreateDoc({
|
||||
onSuccess: (doc) => {
|
||||
router.push(`/docs/${doc.id}`);
|
||||
treeStore.setSelectedNode(doc);
|
||||
togglePanel();
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: createChildrenDoc } = useCreateChildrenDoc({
|
||||
onSuccess: (doc) => {
|
||||
treeStore.addRootNode(doc);
|
||||
treeStore.setSelectedNode(doc);
|
||||
router.push(`/docs/${doc.id}`);
|
||||
togglePanel();
|
||||
},
|
||||
@@ -31,7 +46,14 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
|
||||
};
|
||||
|
||||
const createNewDoc = () => {
|
||||
createDoc();
|
||||
if (currentDoc) {
|
||||
createChildrenDoc({
|
||||
title: t('Untitled page'),
|
||||
parentId: currentDoc.id,
|
||||
});
|
||||
} else {
|
||||
createDoc();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
useDoc,
|
||||
useDocStore,
|
||||
} from '@/features/docs/doc-management/';
|
||||
import { useDocRootTreeStore } from '@/features/docs/doc-tree/stores/useDocRootTree';
|
||||
import { MainLayout } from '@/layouts';
|
||||
import { useBroadcastStore } from '@/stores';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
@@ -60,6 +61,7 @@ const DocPage = ({ id }: DocProps) => {
|
||||
|
||||
const [doc, setDoc] = useState<Doc>();
|
||||
const { setCurrentDoc } = useDocStore();
|
||||
const { setRootId, rootId } = useDocRootTreeStore();
|
||||
const { addTask } = useBroadcastStore();
|
||||
const queryClient = useQueryClient();
|
||||
const { replace } = useRouter();
|
||||
@@ -73,6 +75,13 @@ const DocPage = ({ id }: DocProps) => {
|
||||
}
|
||||
}, [doc?.title]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
console.log('exit');
|
||||
setRootId(undefined);
|
||||
};
|
||||
}, [setRootId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!docQuery || isFetching) {
|
||||
return;
|
||||
@@ -80,7 +89,10 @@ const DocPage = ({ id }: DocProps) => {
|
||||
|
||||
setDoc(docQuery);
|
||||
setCurrentDoc(docQuery);
|
||||
}, [docQuery, setCurrentDoc, isFetching]);
|
||||
if (!rootId) {
|
||||
setRootId(docQuery.id);
|
||||
}
|
||||
}, [docQuery, setCurrentDoc, setRootId, rootId, isFetching]);
|
||||
|
||||
/**
|
||||
* We add a broadcast task to reset the query cache
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { TreeViewDataType } from '@/features/docs/doc-tree/types/tree';
|
||||
import {
|
||||
DataType,
|
||||
LeftPanelDocContent,
|
||||
} from '@/features/left-panel/components/LeftPanelDocContent';
|
||||
|
||||
const initialData: TreeViewDataType<DataType>[] = [
|
||||
{ id: 'Noeud #1', name: 'Noeud #1', children: [] },
|
||||
{ id: 'Noeud #2', name: 'Noeud #2', children: [] },
|
||||
{
|
||||
id: 'Noeud #3',
|
||||
name: 'Noeud #3',
|
||||
childrenCount: 0,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
id: 'Noeud #4',
|
||||
name: 'Noeud #4',
|
||||
children: [
|
||||
{ id: 'Noeud #4.1', name: 'Noeud #4.1' },
|
||||
{ id: 'Noeud #4.2', name: 'Noeud #4.2' },
|
||||
{ id: 'Noeud #4.3', name: 'Noeud #4.3' },
|
||||
],
|
||||
},
|
||||
{ id: 'Noeud #5', name: 'Noeud #5', children: [] },
|
||||
{ id: 'Noeud #6', name: 'Noeud #6', children: [] },
|
||||
{ id: 'Noeud #7', name: 'Noeud #7', children: [] },
|
||||
{
|
||||
id: 'Noeud #8 fjdsk nfjksdn fjksd nfjdks nkjfsdn fjkds',
|
||||
name: 'Noeud #8 hfi sfd hjk sd shjf bdsjhs fbdjhfsdbj kj bq',
|
||||
children: [],
|
||||
},
|
||||
];
|
||||
|
||||
export default function Test() {
|
||||
return <LeftPanelDocContent />;
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
@import url('../cunningham/cunningham-style.css');
|
||||
@import url("@fontsource/material-icons");
|
||||
|
||||
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
@@ -41,3 +44,26 @@ main ::-webkit-scrollbar-thumb:hover,
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
}
|
||||
|
||||
.material-icons-filled {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px; /* Preferred icon size */
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
|
||||
/* Support for all WebKit browsers. */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
/* Support for Safari and Chrome. */
|
||||
text-rendering: optimizeLegibility;
|
||||
/* Support for Firefox. */
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
/* Support for IE. */
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
|
||||
+232
-3
@@ -969,6 +969,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/runtime@^7.9.2":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.9.tgz#aa4c6facc65b9cb3f87d75125ffd47781b475433"
|
||||
integrity sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/template@^7.25.9", "@babel/template@^7.3.3":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016"
|
||||
@@ -1482,6 +1489,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/material-icons-outlined/-/material-icons-outlined-5.0.13.tgz#f8f2a669cb5bdc45fb3ca41f057bc149e3484695"
|
||||
integrity sha512-mQxKJcFiwclTJd0G5fUg0gJ/ZszdaZRSIMFkvbPvMUteA9aSFzFswHr9Yuacw+x4wlBl7GlsVCujAPaBeLv/dw==
|
||||
|
||||
"@fontsource/material-icons@^5.1.1":
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/material-icons/-/material-icons-5.1.1.tgz#5b9b70766a8161af627b4c1b7c8e9b129747d0a2"
|
||||
integrity sha512-l1EhBIh9US1RMiiKEJ+/FTFvHZIU3cpn0MmxSZA6Ip2C/Szwca6h2xqNg/OTIOFWADune7b/rhtypeDbjHrZzA==
|
||||
|
||||
"@formatjs/[email protected]":
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.2.tgz#0ee291effe7ee2c340742a6c95d92eacb5e6c00a"
|
||||
@@ -1988,6 +2000,11 @@
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@juggle/resize-observer@^3.3.1":
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
|
||||
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
|
||||
|
||||
"@keyv/serialize@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@keyv/serialize/-/serialize-1.0.2.tgz#72507c4be94d8914434a4aa80661f8ac6131967f"
|
||||
@@ -2439,6 +2456,95 @@
|
||||
dependencies:
|
||||
"@opentelemetry/core" "^1.1.0"
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1"
|
||||
integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67"
|
||||
integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8"
|
||||
integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b"
|
||||
integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1"
|
||||
integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e"
|
||||
integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30"
|
||||
integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2"
|
||||
integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e"
|
||||
integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee"
|
||||
integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243"
|
||||
integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6"
|
||||
integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==
|
||||
|
||||
"@parcel/[email protected]":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947"
|
||||
integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==
|
||||
|
||||
"@parcel/watcher@^2.4.1":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200"
|
||||
integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
is-glob "^4.0.3"
|
||||
micromatch "^4.0.5"
|
||||
node-addon-api "^7.0.0"
|
||||
optionalDependencies:
|
||||
"@parcel/watcher-android-arm64" "2.5.1"
|
||||
"@parcel/watcher-darwin-arm64" "2.5.1"
|
||||
"@parcel/watcher-darwin-x64" "2.5.1"
|
||||
"@parcel/watcher-freebsd-x64" "2.5.1"
|
||||
"@parcel/watcher-linux-arm-glibc" "2.5.1"
|
||||
"@parcel/watcher-linux-arm-musl" "2.5.1"
|
||||
"@parcel/watcher-linux-arm64-glibc" "2.5.1"
|
||||
"@parcel/watcher-linux-arm64-musl" "2.5.1"
|
||||
"@parcel/watcher-linux-x64-glibc" "2.5.1"
|
||||
"@parcel/watcher-linux-x64-musl" "2.5.1"
|
||||
"@parcel/watcher-win32-arm64" "2.5.1"
|
||||
"@parcel/watcher-win32-ia32" "2.5.1"
|
||||
"@parcel/watcher-win32-x64" "2.5.1"
|
||||
|
||||
"@pkgr/core@^0.1.0":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
|
||||
@@ -3355,6 +3461,21 @@
|
||||
"@react-types/shared" "^3.27.0"
|
||||
"@swc/helpers" "^0.5.0"
|
||||
|
||||
"@react-dnd/asap@^4.0.0":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.1.tgz#5291850a6b58ce6f2da25352a64f1b0674871aab"
|
||||
integrity sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==
|
||||
|
||||
"@react-dnd/invariant@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-2.0.0.tgz#09d2e81cd39e0e767d7da62df9325860f24e517e"
|
||||
integrity sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==
|
||||
|
||||
"@react-dnd/shallowequal@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a"
|
||||
integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==
|
||||
|
||||
"@react-pdf/[email protected]":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/fns/-/fns-3.0.0.tgz#2e0137d48b14c531b2f6a9214cb36ea2a7aea3ba"
|
||||
@@ -6313,6 +6434,13 @@ chokidar@^3.5.2, chokidar@^3.5.3:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
chokidar@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30"
|
||||
integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==
|
||||
dependencies:
|
||||
readdirp "^4.0.1"
|
||||
|
||||
[email protected]:
|
||||
version "11.7.1"
|
||||
resolved "https://registry.yarnpkg.com/chromatic/-/chromatic-11.7.1.tgz#9de59dd9d0e2a847627bccd959f05881335b524e"
|
||||
@@ -6362,7 +6490,7 @@ clone@^2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
|
||||
integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
|
||||
|
||||
clsx@^2.0.0, clsx@^2.1.1:
|
||||
[email protected], clsx@^2.0.0, clsx@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
|
||||
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
|
||||
@@ -6882,6 +7010,11 @@ [email protected]:
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
|
||||
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
|
||||
|
||||
detect-libc@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
|
||||
|
||||
detect-libc@^2.0.2, detect-libc@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700"
|
||||
@@ -6939,6 +7072,15 @@ dir-glob@^3.0.1:
|
||||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
[email protected]:
|
||||
version "14.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.1.tgz#76d000e41c494983210fb20a48b835f81a203c2e"
|
||||
integrity sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A==
|
||||
dependencies:
|
||||
"@react-dnd/asap" "^4.0.0"
|
||||
"@react-dnd/invariant" "^2.0.0"
|
||||
redux "^4.1.1"
|
||||
|
||||
doctrine@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
|
||||
@@ -8815,6 +8957,11 @@ immediate@~3.0.5:
|
||||
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
|
||||
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
|
||||
|
||||
immutable@^5.0.2:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.0.3.tgz#aa037e2313ea7b5d400cd9298fa14e404c933db1"
|
||||
integrity sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==
|
||||
|
||||
import-fresh@^3.2.1, import-fresh@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
@@ -10284,6 +10431,11 @@ [email protected]:
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
|
||||
|
||||
"memoize-one@>=3.1.1 <6":
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
||||
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
||||
|
||||
memoize-one@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
||||
@@ -10619,7 +10771,7 @@ micromark@^3.0.0:
|
||||
micromark-util-types "^1.0.1"
|
||||
uvu "^0.5.0"
|
||||
|
||||
micromatch@^4.0.4, micromatch@^4.0.8:
|
||||
micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
||||
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
||||
@@ -10800,6 +10952,11 @@ node-abi@^3.61.0:
|
||||
dependencies:
|
||||
semver "^7.3.5"
|
||||
|
||||
node-addon-api@^7.0.0:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
|
||||
integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
|
||||
|
||||
node-ensure@^0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7"
|
||||
@@ -11709,6 +11866,17 @@ [email protected]:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
[email protected]:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-arborist/-/react-arborist-3.4.0.tgz#8ef3de2c81d3b8cea0f4f4575c1971bd80c556c5"
|
||||
integrity sha512-QI46oRGXJr0oaQfqqVobIiIoqPp5Y5gM69D2A2P7uHVif+X75XWnScR5drC7YDKgJ4CXVaDeFwnYKOWRRfncMg==
|
||||
dependencies:
|
||||
react-dnd "^14.0.3"
|
||||
react-dnd-html5-backend "^14.0.3"
|
||||
react-window "^1.8.10"
|
||||
redux "^5.0.0"
|
||||
use-sync-external-store "^1.2.0"
|
||||
|
||||
[email protected]:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/react-aria-components/-/react-aria-components-1.3.2.tgz#dee58665210330ec12843e6393ef5cc28ff9a9da"
|
||||
@@ -11871,6 +12039,24 @@ react-aria@^3.34.2, react-aria@^3.37.0:
|
||||
"@react-aria/visually-hidden" "^3.8.19"
|
||||
"@react-types/shared" "^3.27.0"
|
||||
|
||||
react-dnd-html5-backend@^14.0.3:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz#b35a3a0c16dd3a2bfb5eb7ec62cf0c2cace8b62f"
|
||||
integrity sha512-6ONeqEC3XKVf4eVmMTe0oPds+c5B9Foyj8p/ZKLb7kL2qh9COYxiBHv3szd6gztqi/efkmriywLUVlPotqoJyw==
|
||||
dependencies:
|
||||
dnd-core "14.0.1"
|
||||
|
||||
react-dnd@^14.0.3:
|
||||
version "14.0.5"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.5.tgz#ecf264e220ae62e35634d9b941502f3fca0185ed"
|
||||
integrity sha512-9i1jSgbyVw0ELlEVt/NkCUkxy1hmhJOkePoCH713u75vzHGyXhPDm28oLfc2NMSBjZRM1Y+wRjHXJT3sPrTy+A==
|
||||
dependencies:
|
||||
"@react-dnd/invariant" "^2.0.0"
|
||||
"@react-dnd/shallowequal" "^2.0.0"
|
||||
dnd-core "14.0.1"
|
||||
fast-deep-equal "^3.1.3"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
|
||||
react-dom@*, [email protected]:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
|
||||
@@ -12058,6 +12244,14 @@ react-transition-group@^4.3.0:
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react-window@^1.8.10:
|
||||
version "1.8.11"
|
||||
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.11.tgz#a857b48fa85bd77042d59cc460964ff2e0648525"
|
||||
integrity sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
memoize-one ">=3.1.1 <6"
|
||||
|
||||
react@*, [email protected]:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
@@ -12087,6 +12281,11 @@ readable-stream@~2.3.6:
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readdirp@^4.0.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d"
|
||||
integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==
|
||||
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||
@@ -12102,6 +12301,18 @@ redent@^3.0.0:
|
||||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
redux@^4.1.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
|
||||
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
redux@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b"
|
||||
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
|
||||
|
||||
reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9"
|
||||
@@ -12498,6 +12709,17 @@ safe-regex-test@^1.0.3, safe-regex-test@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
[email protected]:
|
||||
version "1.83.4"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.83.4.tgz#5ccf60f43eb61eeec300b780b8dcb85f16eec6d1"
|
||||
integrity sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==
|
||||
dependencies:
|
||||
chokidar "^4.0.0"
|
||||
immutable "^5.0.2"
|
||||
source-map-js ">=0.6.2 <2.0.0"
|
||||
optionalDependencies:
|
||||
"@parcel/watcher" "^2.4.1"
|
||||
|
||||
sax@^1.2.4:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
|
||||
@@ -12806,7 +13028,7 @@ source-list-map@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
|
||||
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
|
||||
|
||||
source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.1:
|
||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||
@@ -13911,6 +14133,13 @@ use-latest@^1.2.1:
|
||||
dependencies:
|
||||
use-isomorphic-layout-effect "^1.1.1"
|
||||
|
||||
[email protected]:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/use-resize-observer/-/use-resize-observer-9.1.0.tgz#14735235cf3268569c1ea468f8a90c5789fc5c6c"
|
||||
integrity sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==
|
||||
dependencies:
|
||||
"@juggle/resize-observer" "^3.3.1"
|
||||
|
||||
use-sidecar@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb"
|
||||
|
||||
Reference in New Issue
Block a user