Added outlineListData for asset hierarchy
This commit is contained in:
@@ -3,17 +3,7 @@ import { AddIcon, ChevronIcon, CollapseAllIcon } from "../../icons/ExportIcons";
|
|||||||
import { OutlinePanelProps } from "./OutlinePanel";
|
import { OutlinePanelProps } from "./OutlinePanel";
|
||||||
import TreeNode from "./TreeNode";
|
import TreeNode from "./TreeNode";
|
||||||
import Search from "./Search";
|
import Search from "./Search";
|
||||||
|
import { AssetGroupChild } from "../../data/OutlineListData";
|
||||||
export interface AssetGroupChild {
|
|
||||||
groupUuid?: string;
|
|
||||||
groupName?: string;
|
|
||||||
isExpanded?: boolean;
|
|
||||||
children?: AssetGroupChild[];
|
|
||||||
modelUuid?: string;
|
|
||||||
modelName?: string;
|
|
||||||
isVisible?: boolean;
|
|
||||||
isLocked?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
type DropAction = "above" | "child" | "below" | "none";
|
type DropAction = "above" | "child" | "below" | "none";
|
||||||
|
|
||||||
@@ -39,19 +29,27 @@ export const OutlineList: React.FC<OutlinePanelProps> = ({
|
|||||||
height,
|
height,
|
||||||
width,
|
width,
|
||||||
search,
|
search,
|
||||||
|
data,
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||||
const [isPanelOpen, setIsPanelOpen] = useState(true);
|
const [isPanelOpen, setIsPanelOpen] = useState(true);
|
||||||
const [draggedNode, setDraggedNode] = useState<AssetGroupChild | null>(null);
|
const [draggedNode, setDraggedNode] = useState<AssetGroupChild | null>(null);
|
||||||
const [searchValue, setSearchValue] = useState("");
|
const [searchValue, setSearchValue] = useState("");
|
||||||
const [hierarchy, setHierarchy] = useState<AssetGroupChild[]>([
|
const [hierarchy, setHierarchy] = useState<AssetGroupChild[]>(data);
|
||||||
{ modelUuid: "a1", modelName: "Asset 1", isVisible: true, isLocked: false, children: [] },
|
|
||||||
{ modelUuid: "a2", modelName: "Asset 2", isVisible: true, isLocked: false, children: [] },
|
useEffect(() => {
|
||||||
{ modelUuid: "a3", modelName: "Asset 3", isVisible: true, isLocked: false, children: [] },
|
const handleClickOutside = (event: MouseEvent): void => {
|
||||||
{ modelUuid: "a4", modelName: "Asset 4", isVisible: true, isLocked: false, children: [] },
|
const target = event.target as HTMLElement;
|
||||||
{ modelUuid: "a5", modelName: "Asset 5", isVisible: true, isLocked: false, children: [] },
|
if (!target.closest(".outline-card")) {
|
||||||
{ modelUuid: "a6", modelName: "Asset 6", isVisible: true, isLocked: false, children: [] },
|
setSelectedId(null);
|
||||||
]);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleDragStart = (item: AssetGroupChild) => {
|
const handleDragStart = (item: AssetGroupChild) => {
|
||||||
setDraggedNode(item);
|
setDraggedNode(item);
|
||||||
@@ -120,10 +118,8 @@ export const OutlineList: React.FC<OutlinePanelProps> = ({
|
|||||||
|
|
||||||
const updatedHierarchy = [...hierarchy];
|
const updatedHierarchy = [...hierarchy];
|
||||||
|
|
||||||
// remove old reference
|
|
||||||
if (!removeFromHierarchy(draggedItem, updatedHierarchy)) return;
|
if (!removeFromHierarchy(draggedItem, updatedHierarchy)) return;
|
||||||
|
|
||||||
// insert in new location
|
|
||||||
if (!insertByDropAction(draggedItem, targetId, dropAction, updatedHierarchy)) {
|
if (!insertByDropAction(draggedItem, targetId, dropAction, updatedHierarchy)) {
|
||||||
updatedHierarchy.push(draggedItem);
|
updatedHierarchy.push(draggedItem);
|
||||||
}
|
}
|
||||||
@@ -215,19 +211,6 @@ export const OutlineList: React.FC<OutlinePanelProps> = ({
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
|
||||||
const handleClickOutside = (event: MouseEvent): void => {
|
|
||||||
const target = event.target as HTMLElement;
|
|
||||||
if (!target.closest(".outline-card")) {
|
|
||||||
setSelectedId(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("mousedown", handleClickOutside);
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("mousedown", handleClickOutside);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const filterHierarchy = (items: AssetGroupChild[], query: string): AssetGroupChild[] => {
|
const filterHierarchy = (items: AssetGroupChild[], query: string): AssetGroupChild[] => {
|
||||||
if (!query.trim()) return items;
|
if (!query.trim()) return items;
|
||||||
@@ -240,7 +223,6 @@ export const OutlineList: React.FC<OutlinePanelProps> = ({
|
|||||||
|
|
||||||
const filteredChildren = item.children ? filterHierarchy(item.children, query) : [];
|
const filteredChildren = item.children ? filterHierarchy(item.children, query) : [];
|
||||||
|
|
||||||
// If this node or any of its children match, keep it
|
|
||||||
if (matches || filteredChildren.length > 0) {
|
if (matches || filteredChildren.length > 0) {
|
||||||
return { ...item, children: filteredChildren };
|
return { ...item, children: filteredChildren };
|
||||||
}
|
}
|
||||||
@@ -248,6 +230,7 @@ export const OutlineList: React.FC<OutlinePanelProps> = ({
|
|||||||
})
|
})
|
||||||
.filter(Boolean) as AssetGroupChild[];
|
.filter(Boolean) as AssetGroupChild[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredHierarchy = filterHierarchy(hierarchy, searchValue);
|
const filteredHierarchy = filterHierarchy(hierarchy, searchValue);
|
||||||
|
|
||||||
const handleRename = (id: string, newName: string) => {
|
const handleRename = (id: string, newName: string) => {
|
||||||
@@ -311,7 +294,6 @@ export const OutlineList: React.FC<OutlinePanelProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* List */}
|
|
||||||
{isPanelOpen && (
|
{isPanelOpen && (
|
||||||
<div className="outline-content">
|
<div className="outline-content">
|
||||||
{filteredHierarchy.map((node) => (
|
{filteredHierarchy.map((node) => (
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { OutlineList } from "./OutlineList ";
|
import { OutlineList } from "./OutlineList ";
|
||||||
|
import { AssetGroupChild } from "../../data/OutlineListData";
|
||||||
|
|
||||||
export interface OutlinePanelProps {
|
export interface OutlinePanelProps {
|
||||||
textColor?: string;
|
textColor?: string;
|
||||||
@@ -11,6 +12,7 @@ export interface OutlinePanelProps {
|
|||||||
height?: string;
|
height?: string;
|
||||||
width?: string;
|
width?: string;
|
||||||
search?: boolean;
|
search?: boolean;
|
||||||
|
data: AssetGroupChild[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const OutlinePanel: React.FC<OutlinePanelProps> = (props) => {
|
const OutlinePanel: React.FC<OutlinePanelProps> = (props) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { AssetGroupChild, DEFAULT_PRAMS } from "./OutlineList ";
|
import { DEFAULT_PRAMS } from "./OutlineList ";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {
|
import {
|
||||||
ChevronIcon,
|
ChevronIcon,
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
KebebIcon,
|
KebebIcon,
|
||||||
LockIcon,
|
LockIcon,
|
||||||
} from "../../icons/ExportIcons";
|
} from "../../icons/ExportIcons";
|
||||||
|
import { AssetGroupChild } from "../../data/OutlineListData";
|
||||||
|
|
||||||
interface TreeNodeProps {
|
interface TreeNodeProps {
|
||||||
item: AssetGroupChild;
|
item: AssetGroupChild;
|
||||||
@@ -120,15 +121,12 @@ const TreeNode: React.FC<TreeNodeProps> = ({
|
|||||||
id={item.modelUuid || item.groupUuid}
|
id={item.modelUuid || item.groupUuid}
|
||||||
onClick={toggleSelect}
|
onClick={toggleSelect}
|
||||||
>
|
>
|
||||||
{/* 👇 Flex container for the entire row */}
|
|
||||||
<div
|
<div
|
||||||
className="node-wrapper"
|
className="node-wrapper"
|
||||||
style={{ display: "flex", alignItems: "center", width: "100%" }}
|
style={{ display: "flex", alignItems: "center", width: "100%" }}
|
||||||
>
|
>
|
||||||
{/* Indentation spacer — only affects left side */}
|
|
||||||
<div style={{ width: `${level * 20}px`, flexShrink: 0 }} />
|
<div style={{ width: `${level * 20}px`, flexShrink: 0 }} />
|
||||||
|
|
||||||
{/* Expand button (only for groups) */}
|
|
||||||
{isGroupNode ? (
|
{isGroupNode ? (
|
||||||
<button
|
<button
|
||||||
className="expand-button"
|
className="expand-button"
|
||||||
@@ -140,7 +138,7 @@ const TreeNode: React.FC<TreeNodeProps> = ({
|
|||||||
<ChevronIcon isOpen={isExpanded} />
|
<ChevronIcon isOpen={isExpanded} />
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ width: "20px", flexShrink: 0 }} /> // match expand button width
|
<div style={{ width: "20px", flexShrink: 0 }} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="node-icon" style={{ flexShrink: 0 }}>
|
<div className="node-icon" style={{ flexShrink: 0 }}>
|
||||||
@@ -185,7 +183,6 @@ const TreeNode: React.FC<TreeNodeProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Controls (always visible, never shrink) */}
|
|
||||||
<div
|
<div
|
||||||
className="node-controls"
|
className="node-controls"
|
||||||
style={{ display: "flex", gap: "4px", flexShrink: 0 }}
|
style={{ display: "flex", gap: "4px", flexShrink: 0 }}
|
||||||
|
|||||||
19
src/data/OutlineListData.tsx
Normal file
19
src/data/OutlineListData.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export const OutlineListData = [
|
||||||
|
{ modelUuid: "a1", modelName: "Asset 1", isVisible: true, isLocked: false, children: [] },
|
||||||
|
{ modelUuid: "a2", modelName: "Asset 2", isVisible: true, isLocked: false, children: [] },
|
||||||
|
{ modelUuid: "a3", modelName: "Asset 3", isVisible: true, isLocked: false, children: [] },
|
||||||
|
{ modelUuid: "a4", modelName: "Asset 4", isVisible: true, isLocked: false, children: [] },
|
||||||
|
{ modelUuid: "a5", modelName: "Asset 5", isVisible: true, isLocked: false, children: [] },
|
||||||
|
{ modelUuid: "a6", modelName: "Asset 6", isVisible: true, isLocked: false, children: [] },
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface AssetGroupChild {
|
||||||
|
groupUuid?: string;
|
||||||
|
groupName?: string;
|
||||||
|
isExpanded?: boolean;
|
||||||
|
children?: AssetGroupChild[];
|
||||||
|
modelUuid?: string;
|
||||||
|
modelName?: string;
|
||||||
|
isVisible?: boolean;
|
||||||
|
isLocked?: boolean;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import OutlinePanel from "../components/ui/OutlinePanel";
|
import OutlinePanel from "../components/ui/OutlinePanel";
|
||||||
|
import { OutlineListData } from "../data/OutlineListData";
|
||||||
|
|
||||||
const SceneView = () => {
|
const SceneView = () => {
|
||||||
return (
|
return (
|
||||||
@@ -11,6 +12,7 @@ const SceneView = () => {
|
|||||||
// eyeIconColor=""
|
// eyeIconColor=""
|
||||||
// backgroundColor=""
|
// backgroundColor=""
|
||||||
search={true}
|
search={true}
|
||||||
|
data={OutlineListData}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user