Skip to content

Commit

Permalink
Merge pull request #563 from subugoe/global-tree-selection
Browse files Browse the repository at this point in the history
Add the feature of Global Tree
  • Loading branch information
orlinmalkja authored Feb 10, 2025
2 parents 67b817b + df7f552 commit 24003d0
Show file tree
Hide file tree
Showing 18 changed files with 319 additions and 164 deletions.
31 changes: 27 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import PanelsWrapper from './components/PanelsWrapper'
import { FC } from 'react'
import { FC, useEffect } from 'react'

import { configStore } from '@/store/ConfigStore.tsx'
import { dataStore } from '@/store/DataStore.tsx'

import TopBar from '@/components/TopBar'
import GlobalTree from '@/components/tree/GlobalTree.tsx'

import { createCollectionNodes } from '@/utils/tree.ts'
import PanelsWrapper from '@/components/PanelsWrapper.tsx'

interface AppProps {
customConfig: Config
Expand All @@ -12,10 +17,28 @@ const App: FC<AppProps> = ({ customConfig }) => {
const addCustomConfig = configStore((state) => state.addCustomConfig)
addCustomConfig(customConfig)

const collections = dataStore(state => state.collections)
const setTreeNodes = dataStore(state => state.setTreeNodes)


useEffect(() => {
async function initTree(collections: CollectionMap) {
const nodes = await createCollectionNodes(collections)
if (!nodes) return

setTreeNodes(nodes)
}

initTree(collections)
}, [collections])

Check warning on line 33 in src/App.tsx

View workflow job for this annotation

GitHub Actions / build (18)

React Hook useEffect has a missing dependency: 'setTreeNodes'. Either include it or remove the dependency array

Check warning on line 33 in src/App.tsx

View workflow job for this annotation

GitHub Actions / build (20)

React Hook useEffect has a missing dependency: 'setTreeNodes'. Either include it or remove the dependency array

return (
<div className="tido t-flex t-flex-col">
<TopBar />
<PanelsWrapper />
<TopBar/>
<div className="t-flex">
<GlobalTree/>
<PanelsWrapper/>
</div>
</div>
)
}
Expand Down
42 changes: 42 additions & 0 deletions src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { FC, ReactNode, useEffect, useState } from 'react'

import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'

interface ModalProps {
children: ReactNode,
TriggerButton?: ReactNode,
showPopover?: boolean,
position?: Position
}

const Modal: FC<ModalProps> = ({
children, TriggerButton, showPopover, position
}) => {

const [isOpen, setIsOpen] = useState(false)

const handleOpenChange = (open: boolean) => {
setIsOpen(open)
}

useEffect(() => {
if (showPopover) setIsOpen(true)
}, [position])

Check warning on line 24 in src/components/Modal.tsx

View workflow job for this annotation

GitHub Actions / build (18)

React Hook useEffect has a missing dependency: 'showPopover'. Either include it or remove the dependency array

Check warning on line 24 in src/components/Modal.tsx

View workflow job for this annotation

GitHub Actions / build (20)

React Hook useEffect has a missing dependency: 'showPopover'. Either include it or remove the dependency array

return <div className="local-tree-modal">
<Popover open={isOpen} onOpenChange={handleOpenChange}>
<PopoverTrigger asChild>
{TriggerButton}
</PopoverTrigger>
<PopoverContent
style={{
top: `${position?.y + 40}px`,
left: `${position?.x}px`,
}}>
{children}
</PopoverContent>
</Popover>
</div>
}

export default Modal
2 changes: 1 addition & 1 deletion src/components/PanelsWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { configStore } from '@/store/ConfigStore.tsx'
const PanelsWrapper: FC = () => {
const config = configStore(state => state.config)
const panels = config?.panels
return <div className="t-flex t-h-full t-flex-row t-ml-[6%]"> {
return <div className="t-flex t-h-full t-ml-4 t-flex-row"> {
panels?.map((panelConfig, i: number) => (<Panel config={panelConfig} key={i}/>))
}</div>
}
Expand Down
41 changes: 36 additions & 5 deletions src/components/TopBar.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,52 @@
import { FC } from 'react'
import { FC, useState } from 'react'

import { configStore } from '@/store/ConfigStore.tsx'

import Modal from '@/components/Modal.tsx'
import TreeSelectionModalContent from '@/components/tree-modal/TreeSelectionModalContent.tsx'
import IconRenderer from '@/components/base/IconRenderer.tsx'

import { tree } from '@/utils/icons'
import { cross } from '@/utils/icons'
import { dataStore } from '@/store/DataStore.tsx'

import TreeSelectionModal from '@/components/TreeSelectionModal'

const TopBar: FC = () => {

const [iconHtmlString, setIconHtmlString] = useState(tree)
const globalTree = configStore(state => state.config.globalTree)

const setShowGlobalTree = dataStore(state => state.setShowGlobalTree)

function toggleIcon() {
if (iconHtmlString === tree) {
// we click the tree icon - now we show the global tree (set the value to true)
setShowGlobalTree(true)
setIconHtmlString(cross)
} else if (iconHtmlString === cross) {
setShowGlobalTree(false)
setIconHtmlString(tree)
}
}

const addButton =
<span
className="t-bg-blue-500 t-text-white t-rounded t-flex t-pl-4 t-items-center t-justify-items-center t-w-16 t-h-10">
New
New
</span>


return <div className="t-flex t-flex-row t-ml-[6%] t-mt-10">
<TreeSelectionModal TriggerButton={addButton}/>
<button className={`t-mr-2 toggle-global-tree ${!globalTree ? 't-hidden' : ''}`} onClick={() => toggleIcon()}>
<IconRenderer
htmlString={iconHtmlString}
width={8}
height={8}/>
</button>
<Modal TriggerButton={addButton}>
<TreeSelectionModalContent/>
</Modal>
</div>

}

export default TopBar
24 changes: 11 additions & 13 deletions src/components/Tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,25 @@ import TreeNode from '@/components/tree/TreeNode'
interface TreeProps {
nodes: TreeNode[],

onSelect(node: TreeNode): void,
onSelect(node: TreeNode, target): void,

onExpand(node: TreeNode): void,

onCollapse(node: TreeNode): void,
getChildren(node: TreeNode): Promise<TreeNode[]>
}

const Tree: FC<TreeProps> = ({ nodes, onSelect, onExpand, onCollapse }) => {
const Tree: FC<TreeProps> = ({ nodes, onSelect, getChildren }) => {


const tree =
nodes.length > 0 &&
nodes.map((collection, i) => (
<div key={i}>
<TreeNode node={collection}/>
</div>
))
nodes?.length > 0 &&
nodes.map((collection, i) => (
<div key={i}>
<TreeNode node={collection}/>
</div>
))


return <div className="tree t-h-96 t-overflow-hidden t-overflow-y-auto">
<TreeProvider onSelect={onSelect} onExpand={onExpand} onCollapse={onCollapse}>
return <div className="tree t-w-96 t-h-96 t-overflow-hidden t-overflow-y-auto">
<TreeProvider onSelect={onSelect} getChildren={getChildren}>
{tree}
</TreeProvider>
</div>
Expand Down
25 changes: 0 additions & 25 deletions src/components/TreeSelectionModal.tsx

This file was deleted.

30 changes: 30 additions & 0 deletions src/components/base/IconRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useEffect, useRef, FC, useState } from 'react'

interface IconRendererProps {
htmlString: string
width?: number,
height?: number
}

const IconRenderer: FC<IconRendererProps> = ({ htmlString, width, height }) => {
const ref = useRef<HTMLInputElement>(null)

const [iconWidth, setIconWidth] = useState(4)
const [iconHeight, setIconHeight] = useState(4)

useEffect(() => {
if (width) setIconWidth(width)
if (height) setIconHeight(height)

if (ref?.current) {
(ref.current as HTMLElement).innerHTML = htmlString
const iconEls = ref.current.children

const iconEl = iconEls[0]
iconEl.classList.add('t-w-' + iconWidth, 't-h-' + iconHeight)
}
}, [htmlString, iconWidth, iconHeight])

Check warning on line 26 in src/components/base/IconRenderer.tsx

View workflow job for this annotation

GitHub Actions / build (18)

React Hook useEffect has missing dependencies: 'height' and 'width'. Either include them or remove the dependency array. If 'setIconWidth' needs the current value of 'width', you can also switch to useReducer instead of useState and read 'width' in the reducer

Check warning on line 26 in src/components/base/IconRenderer.tsx

View workflow job for this annotation

GitHub Actions / build (20)

React Hook useEffect has missing dependencies: 'height' and 'width'. Either include them or remove the dependency array. If 'setIconWidth' needs the current value of 'width', you can also switch to useReducer instead of useState and read 'width' in the reducer

return <div ref={ref}></div>
}
export default IconRenderer
7 changes: 4 additions & 3 deletions src/components/base/InputField.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { FC } from 'react'

interface InputFieldProps {
updateInputValue: (newValue: string) => void
updateInputValue: (newValue: string) => void,
width: number
}

const InputField: FC<InputFieldProps> = ({ updateInputValue }) => {
const InputField: FC<InputFieldProps> = ({ updateInputValue, width }) => {

return <>
<input className="t-border-solid t-border-[1.5px] t-w-[200px] t-h-[30px] t-mb-[10px]"
<input className={`t-border-solid t-border-[1.5px] t-w-${width} t-h-[30px] t-mb-[10px]`}
onChange={(e) => updateInputValue(e.target.value)}/>
</>
}
Expand Down
53 changes: 53 additions & 0 deletions src/components/tree-modal/GlobalTreeSelectionModalContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { FC } from 'react'
import { configStore } from '@/store/ConfigStore.tsx'


interface SelectedItemIndicesType {
collectionUrl: string,
manifestIndex: number,
itemIndex: number,
}

interface GlobalTreeSelectionModalContentProps {
selectedItemIndices: SelectedItemIndicesType,
}

const GlobalTreeSelectionModalContent: FC<GlobalTreeSelectionModalContentProps> = ({ selectedItemIndices }) => {

const panels = configStore(state => state.config.panels)
const addNewPanel = configStore(state => state.addNewPanel)
const updatePanel = configStore(state => state.updatePanel)

const newPanelConfig = {
entrypoint: {
url: selectedItemIndices.collectionUrl,
type: 'collection',
},
manifestIndex: selectedItemIndices.manifestIndex,
itemIndex: selectedItemIndices.itemIndex
}

let buttonsUpdatePanel
if (panels && panels?.length > 0) {
buttonsUpdatePanel = panels?.map((_, i) => <button
className="t-bg-slate-200 t-w-20 t-h-8 t-mr-1 t-rounded-md hover:t-bg-slate-300" key={i}
onClick={() => updatePanel(
newPanelConfig
, i)}>Panel {i + 1}</button>)
}


return (
<div
className="t-flex t-items-center t-h-12 t-border-1 t-border-gray-300 t-px-4 t-py-2 t-shadow-md t-rounded-md ">
<div className="buttons-update-panel t-flex">
{buttonsUpdatePanel}
</div>
<button className="button-new-panel t-bg-slate-200 t-w-24 t-h-8 t-mr-1 t-rounded-md hover:t-bg-slate-300"
onClick={() => addNewPanel(newPanelConfig)}> New
Panel
</button>
</div>)
}

export default GlobalTreeSelectionModalContent
Loading

0 comments on commit 24003d0

Please sign in to comment.